Live data from Hacker News

MySQL and partitioning tables with millions of rows

chrismoos.com

11–20 of 23 posts

Re: MySQL and partitioning tables with millions of rows

#11

had this guy an index on "device_id" and "date_added", there is no way such a query would take 3-4 seconds.

I had indexes on id, user_id, device_id, and date_added, but maybe I was doing something else wrong. I'm not a database expert :(

Were those single indexes like CREATE INDEX index_1 ON Locations(id) CREATE INDEX index_2 ON Locations(user_id) ...?

If you have multiple single column indexes it won't help you here. The mysql query planner probably correctly guessed the table scan was a better option than hash joining the results of two seeks given the machine's limited memory. It also probably underestimated the cost of disk IO on a virtual machine though.

Re: MySQL and partitioning tables with millions of rows

#12
post #8

Earlier quoted context omitted.

ActiveRecord... The SQL was pretty simple I believe..select * from location where device_id = ? order by date_added desc limit 6...something like that. Edit: Also, I don't know how much it matters, but MySQL probably only has ~256mb memory available to it (its hosted on a Xen box).

Queries like that should be very, very fast even with low amounts of ram. Good article, but consider using EXPLAIN a few times first before embarking on such adventures. :)

Definitely want to second the advice to use EXPLAIN.

MySQL has a lot of very specific limitations about when it will and will not use the available indices. It also matters how you created the indices (one index on multiple columns vs multiple indices on individual columns).

For example, if you created a single index with the columns (date_added, device_id) MySQL would not be able to use the index since device_id is the second part of the index, not the first and thus not available for use in the WHERE clause.

See http://dev.mysql.com/doc/refman/5.1/en/mysql-indexes.html for more limitations.

Re: MySQL and partitioning tables with millions of rows

#13
post #10

While the write up was good, the author makes assumptions about what's happening seemingly without checking. He didn't post the actual query or the original and final query plans. Partitioning is a rather complex solution to his problem. See the limitations at http://dev.mysql.com/doc/refman/5.1/en/partitioning-limitati... I can't know for sure since there's not enough information there, but I'd suspect a simple inde…

That's entirely right; to explain a bit more, the reason that index is good is because it's a covering index. You have all the data you need to pull from the table in the index (which you've found via binary search through your B+tree), so you don't need to run out again to the table, and that saves an extra disk seek.

To make a covering index takes longer, so insertion speed drops, but that shouldn't be the hotspot.

Re: MySQL and partitioning tables with millions of rows

#14
post #13
post #10

While the write up was good, the author makes assumptions about what's happening seemingly without checking. He didn't post the actual query or the original and final query plans. Partitioning is a rather complex solution to his problem. See the limitations at http://dev.mysql.com/doc/refman/5.1/en/partitioning-limitati... I can't know for sure since there's not enough information there, but I'd suspect a simple inde…

That's entirely right; to explain a bit more, the reason that index is good is because it's a covering index. You have all the data you need to pull from the table in the index (which you've found via binary search through your B+tree), so you don't need to run out again to the table, and that saves an extra disk seek. To make a covering index takes longer, so insertion speed drops, but that shouldn't be the hotspot.

Actually, since he was effectively doing SELECT * ... it still has to go pull the rows from the table after seeking the index. This likely isn't a huge problem though.

To prevent going back to the table in this case, you'd either need the index I mentioned to be the primary key, or a construct like INCLUDE (which mysql appears to lack).

See http://msdn.microsoft.com/en-us/library/ms188783.aspx

Re: MySQL and partitioning tables with millions of rows

#15

had this guy an index on "device_id" and "date_added", there is no way such a query would take 3-4 seconds.

I had indexes on id, user_id, device_id, and date_added, but maybe I was doing something else wrong. I'm not a database expert :(

MySQL can only use one index per query. If you need it be on two or more columns you need a composite index with both columns in, populated from the left. If MySQL finds a column in the index you not keying off (WHERE/SORT etc.) then it will stop processing the index at that point.

The key_len column in the EXPLAIN shows you how far it got through the index, based on the size of the columns. In your case it says 4 which if device id is of type INT it just read one column in the index (though there is probably only one column in that index)

Re: MySQL and partitioning tables with millions of rows

#17
Honestly, the first thing I did was add indexes. On device_id, user_id, and date_added.

I'm using Linode and I kept getting these I/O notifications...and the site would load extremely slow at times.

After looking at the log of my Rails app, I saw that some requests were taking > 20 seconds. I determined that this was some kind of blocking at the database.

I connected to MySQL and ran something simple...

select count(*) from location;

It took a long time...I turned profiling on and saw that it was taking a really long time in "table lock".

I assumed (which probably wasn't a good idea) that it was going through and counting all the rows.

I didn't really know what to make of this..because I didn't think that getting the count would take so long.

I embarked on reading about partitioning, which may have been a solution for a problem that didn't actually exist (based on the feedback here). I attempted to partition (on what I put in the article), and everything seemed much snappier after that. If the indexes should have solved the problem (given that they were correct), I don't know why the location queries were taking so long.

Anyway, I still have lots to learn on the database front, and maybe the fact that my VM had 7MB free of memory was causing weird things to happen, I'm not sure.

Thanks for all the feedback and I have definitely learned a lot in this thread.

kogir:

I'm using MyISAM (which, in retrospect, seems stupid), so I don't even have foreign key constraints (InnoDB only, I believe).

Re: MySQL and partitioning tables with millions of rows

#18

Honestly, the first thing I did was add indexes. On device_id, user_id, and date_added. I'm using Linode and I kept getting these I/O notifications...and the site would load extremely slow at times. After looking at the log of my Rails app, I saw that some requests were taking > 20 seconds. I determined that this was some kind of blocking at the database. I connected to MySQL and ran something simple... select count(…

Can you tell us the size of your query cache and your key cache, if they are enabled? If not, we should talk about enabling them. :-)

Re: MySQL and partitioning tables with millions of rows

#19

Honestly, the first thing I did was add indexes. On device_id, user_id, and date_added. I'm using Linode and I kept getting these I/O notifications...and the site would load extremely slow at times. After looking at the log of my Rails app, I saw that some requests were taking > 20 seconds. I determined that this was some kind of blocking at the database. I connected to MySQL and ran something simple... select count(…

Can you tell us the size of your query cache and your key cache, if they are enabled? If not, we should talk about enabling them. :-)

They are rather low...I figured that would be good on a limited memory configuration (maybe not :( ).

query_cache_limit = 1M query_cache_size = 16M key_buffer = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8

Re: MySQL and partitioning tables with millions of rows

#20

Honestly, the first thing I did was add indexes. On device_id, user_id, and date_added. I'm using Linode and I kept getting these I/O notifications...and the site would load extremely slow at times. After looking at the log of my Rails app, I saw that some requests were taking > 20 seconds. I determined that this was some kind of blocking at the database. I connected to MySQL and ran something simple... select count(…

MySQL does not scan any rows for SELECT COUNT(*) FROM table — the number of records is stored in table metadata. (Mind you, it only works for this kind of query, as soon as you add WHERE the story changes). On the other hand, MyISAM only has table level locks, not row level. I guess it is time for you to analyze what your app does with DB and how it can affect locking…
Post reply on HN