Home » Performance » MySQL » Key Cache Behaviour
| Key Cache Behaviour [message #993] |
Tue, 27 March 2007 12:56  |
bitrockers Messages: 11 Registered: November 2006 Location: Germany |
Junior Member |
|
|
Hi,
I've set up a new website and actually I'm preparing some "load" testing regarding a couple of search queires.
I've seen a behaviour that I cannot explain, so maybe you guys have some answers?
There is Mysql 5.0.30 running on a 64bit Debian Etch distribution. Server has two XEON CPUs and 8 GB of Ram. We mostly use MyIsam tables so I've set the key_buffer to the maximum of 4 GB.
Next there are 31 tables in a seperate database with overall 111 million rows. Each table has an average index size of 100 MB (datasize 170 MB). The "data" is split among 31 tables due to partioning ( so we don't have to deal with MyIsam locking issues too much).
The table structures are identical:
userID1 (int)
userID2 (int)
userVote1 (tinyint)
userVote2 (tinyint)
voteDate1 (datetime)
voteDate2 (datetime)
and only one primary key (index) on the fields (userID1, userID2).
Now our application typically tries to find records where userID1 is given and sometimes userVote1 or userVote2 is queried, e.g.
SELECT userID2 FROM table_1 WHERE userID1 = 100 AND userVote1=2
So far so good. The first time a query is started it typically lasts about 5-10 seconds (sometimes 10-20 seconds) for the query above. Each subsequent query for the specified userID (in the example '100') then only lasts about 0.2 - 0.4 seconds.
This is not due to query cache( because it's still the same when we use SQL_NO_CACHE). I suggest the performance increase is a result of loading the key cache for that table.
When I send random queries for userIDs between 1 and 10000 (which are stored in table table_1) after a couple of queries every following query only needs 2 - 5 seconds. So thats fine (and again I guess a result of the Key Cache).
But: When I start to spread queries to all of the tables (actually 31, userID1 between 1 and 300000) , there's no such a performance increase, altough there should be enough memory for mysql to hold all keys (overall size about 3.1 GB) in RAM.
Do you have any idea, why the "key cache" thing only works, when I spread the queries to about 5 tables. Also using a seperate key cache (SET GLOBAL keycache bla bla) doesn't help.
I've also tried to use LOAD INDEX INTO CACHE table1, table2... but that also doesn't help.
Does anyone have an idea? Our variables regarding key_cache are:
Key_blocks_not_flushed 0
Key_blocks_unused 1.646 k
Key_blocks_used 418 k
Key_read_requests 2.429 M
Key_reads 88 M
Key_write_requests 56 M
Key_writes 36 M
Key_buffer_fraction_% 19,64 %
Would the "Midpoint Insertion Strategy" help?
http://dev.mysql.com/doc/refman/5.1/en/midpoint-insertion.ht ml
If so, what do you guess to set the key_cache_division_limit value?
I appreciate any help.
Greetings
Christian
|
|
| |
| Re: Key Cache Behaviour [message #996 is a reply to message #993 ] |
Tue, 27 March 2007 16:01   |
bitrockers Messages: 11 Registered: November 2006 Location: Germany |
Junior Member |
|
|
Dear Sterin,
thanks for your fast response. Your explaination regarding the OS file cache sounded very reasonable, so I tested my "benchmark" script with a key_buffer size of 2GB. Unfortunately that didn't helped a lot. As I told you its a 8 GB machine, so I've set the following conf-vars in my.cnf:
inno_db_buffer_pool = 1024M (for a couple of innodb tables used)
key_buffer = 2000M
myisam_sort_buffer_size = 1024M
So the OS has around 4GB for file caching. Do you think decreasing one of the mysql-vars would still result in performance increase? My feeling is that 4GB should be really enough 
For the tuning part: In fact, it's a little more complicated compared to what I've posted. In the production system where will be a inner join on a users table ( filled with about 300.000 records), but I'd still concentrate to the tables definition I've posted, because each of that tables has around 3 - 7 million records. So thats the "bottleneck" in fact.
Unfortunately in the production system there will be more than the query I've posted, in fact:
Main queries on that large tables (about 80%) will be
SELECT userVote1, userVote2 FROM table_x WHERE userID1=CONST AND userID2=CONST
(returning maximum one record)
That queries only last a couple of ms, so I don't bother if it will read from key cache or additionally from the data file.
But there are a couple of often (20%) used search queries ( which often will result in a large result between 200-4000 records, and usually last about 2-10 seconds). BTW: When benchmarking those queries I used select count(*) instead of fetching each records, so theres no overhead for the transfer to the client.
SELECT userID2 FROM table_x WHERE userID1 = CONST AND userVote1 = 2 AND userVote2 = 2
SELECT userID2 FROM table_x WHERE userID1 = CONST AND userVote2 IN (1,2)
SELECT userID2 FROM table_x WHERE userID1 = CONST AND userVote1 = 2
SELECT userID2 FROM table_x WHERE userID1 = CONST AND userVote1 = 0 AND userVote2 = 2
So. For "optimal" performance ( index based query) I would have the following indexes, right?
(userID1, userID2, userVote1, userVote2)
(userID1, userVote2, userID2)
(userID1, userVote1, userID2)
(userID1, userVote1, userVote2, userID2)
The only downside is, that each table has about 2 - 7 million records. Creating such additional index would increase the index-file size for the largest table from actually 112MB to around, I guess, 500M at least.
With 31 tables it would increase the overall key size significally so that the index definitly would not fit into the key_buffer
Additionally in the case that MySQL would crash it would took 5 times longer to restore the index files (which actually needs about 2 hours for the whole database).
Do you still think I would benefit from setting that indexes? Is the performance increase for index-only reading large enough compared to have a small index that fits into RAM (and which is used for all search-queries but still needs a datafile lookup)?
Are there any numbers out there about how long does it take for mysql to read non-indexed information from the datafile? I thought when mysql used the index file the lookup wouldn't take so much time?
Are there tools out there that benchmark how long mysql needs for reading from datafile? I think there should be some kind of "BENCHMARCK SELECT ..." where mysql explains how much time each step lasted. Or is something like that out there and I simply don't know about it? 
|
|
|
| Re: Key Cache Behaviour [message #998 is a reply to message #993 ] |
Tue, 27 March 2007 17:10   |
bitrockers Messages: 11 Registered: November 2006 Location: Germany |
Junior Member |
|
|
Damn. Sorry for the long post. I've really overseen that I first should set the indexes properly for the queries I use often. Of course I should add the (userID1, voteDate1, ...) and so on stuff.
But one question remains: Is it better to leave the indexes short (e.g. only set indexes for the where-part), so that possibly more of the index can be held im memory.
Or should I add every index combination, so that the whole query would could be resolved by just looking an the indexes, with the downside that the index-size would be significally higher?
e.g. For the queries above I would set the following index (so that the "where"-lookup can be solved by just looking to the indexes, with additional need for a lookup in the datafile):
1: (userID1, userVote1, userVote2)
2: (userID1, userVote2)
Or should I add for each of the 5 possible queries a seperate index, e.g.
1: (userID1, userVote1, userVote2)
2: (userID1, userVote2, userID2, voteDate2)
3: (userID1, userVote1, userID2, voteDate1)
?
Last but not least another question The second fields in the indexes (userVote1 and userVote2) will only have three possible values: 0, 1, or 2. With a distribution of about
50%: 0
10%: 2
40%: 1
Does it make sense to add the index on that field regarding the distribution of the possible values? (That's why I "forgot" to set the indexes for that column).
[Updated on: Tue, 27 March 2007 17:14]
|
|
| | | | | |
Goto Forum:
Current Time: Sun Jul 5 22:14:32 EDT 2009
Total time taken to generate the page: 0.00614 seconds |