You should just disable the query cache with
[mysqld]
query_cache_size = 0
and then restart mysql. Why would I suggest that ???
The Query Cache will always butt heads with InnoDB. It would be nice if InnoDB's MVCC would let queries be served from the query cache if modifications do not affect repeatable reads for other transactions. Unfortunately, InnoDB just does not do that. Apparently, you have a lot of queries that get invalidated rather quickly and are probably not being reused.
For InnoDB under MySQL 4.0, the query cache was disabled for transactions. For MySQL 4.1+, InnoDB plays traffic cop when allowing access to the query cache on a per-table basis.
From the perspective of your question, I would say that the justification of removing the query cache is not so much the overhead, but how InnoDB manages it.
For more information on how InnoDB interacts with the query cache, please read pages 213-215 of the book "High Performance MySQL (Second Edition)".
If all or the majority of your data is MyISAM, you could go with your original idea of using SQL_NO_CACHE.
If you have a mix of InnoDB and MyISAM, you will have to find the right balance for your application based on on how high your cache misses are. In fact, pages 209-210 of the same book point out reasons for cache misses :
- The query is not cacheable, either because it contains a nondeterministic construct (such as CURRENT_DATE) or because its
result set is too large to store.Both types of uncacheable queries
increment the Qcache_not_cached status variable.
- The server has never seen the query before, so it never had the chance to cache its result.
- The query's result was previously cached, but the server removed it. This can happen because there wasn't enough memory to keep it, because
someone instructed the server to remove it, or because it was
invalidated
and the root causes of high cache misses with few uncacheable queries may be :
- The query cache is not warm yet. That is the server hasn't had a chance to fill the cache with result sets.
- The server is seeing queries it hasn't seen before. If you do not have a lot of repeated queries, this can happen even after the cache
is warmed up.
- There are a lot of cache invalidations.
UPDATE 2012-09-06 10:10 EDT
Looking your latest updated info, you have query_cache_limit
set to 1048576 (1M). This limits any result set to 1M. If you retrieve anything bigger, it will simply not be cached. While you have have query_cache_size
set to 104857600 (100M), this only allows for 100 cached results set in a perfect world. If you perform hundreds of queries, fragmentation will come about rather quickly. You also have 4096 (4K) as the minimum size result set. Unfortunately, mysql has no internal mechanism for defragmenting the query cache.
If you must have the query cache and you have so much RAM, you could execute the following:
SET GLOBAL query_cache_size = 0;
SELECT SLEEP(60);
SET GLOBAL query_cache_size = 1024 * 1024 * 1024;
in order to purge the query cache. You lose all cached results, so run these lines during off-peak hours.
I would also assign the following:
- query_cache_size = 1G
- query_cache_limit = 8M
That leaves 23G of RAM. I would raise the following:
- innodb_buffer_pool_size = 12G
- key_buffer_size = 4G
That leaves 7G. This should be adequate for OS and DB Connections.
Keep in mind that the key buffer caches only MyISAM index pages, while the InnoDB Buffer Pool caches data and indexes.
One more recommendation: upgrade to MySQL 5.5 so you can configure InnoDB for multiple CPU and multiple threads for read/write I/O.
See my earlier posts on using MySQL 5.5 in conjunction with accessing multiple CPUs for InnoDB
UPDATE 2012-09-06 14:56 EDT
My method for clearing the query cache is rather extreme because it hoses cached data and forms a completely different segment of RAM. As you did point out in your comment, FLUSH QUERY CACHE
(as you suggested) or even RESET QUERY CACHE
would be better. For clarification, when I said "no internal mechanism," I meant exactly that. Defragmentation is needed and has to be done manually. It would need to be crontab'd.
If you do DML (INSERTs, UPDATEs, DELETEs) on InnoDB more often than on MyISAM, I would say remove the query cache altogether, which I said in the beginning.
There is most definitely a difference between SHOW STATUS;
and SHOW GLOBAL STATUS;
SHOW GLOBAL STATUS;
will give you status variables that have updated since mysqld started for all sessions that are connected or have ever been connected.
SHOW STATUS;
will give you status variables that have updated within your session. The command can also be expressed as SHOW SESSION STATUS;
(As the MySQL Documentation says, it displays the status values for the current connection).
To physically show the difference, the information_schema database has them separated as
INFORMATION_SCHEMA.GLOBAL_STATUS
INFORMATION_SCHEMA.SESSION_STATUS
These information_schema tables have been around since MySQL 5.1.12.
Why the difference?
To thoroughly demonstrate the difference, let me run an INNER JOIN of these tables to show which values are different. Here is the query:
SELECT a.variable_name,a.variable_value,b.variable_value
FROM information_schema.global_status A INNER join information_schema.session_status B
USING (variable_name) WHERE A.variable_value <> B.variable_value;
Please note the output:
mysql> SELECT A.variable_name,A.variable_value,B.variable_value
-> FROM information_schema.global_status A INNER join information_schema.session_status B
-> USING (variable_name) WHERE A.variable_value <> B.variable_value;
+---------------------------+----------------+----------------+
| variable_name | variable_value | variable_value |
+---------------------------+----------------+----------------+
| BYTES_RECEIVED | 123641576598 | 7757 |
| BYTES_SENT | 149888451047 | 300001 |
| COM_ADMIN_COMMANDS | 121915 | 0 |
| COM_ALTER_TABLE | 111 | 0 |
| COM_BEGIN | 1 | 0 |
| COM_CALL_PROCEDURE | 530 | 0 |
| COM_CHANGE_DB | 1623 | 1 |
| COM_COMMIT | 19220 | 0 |
| COM_CREATE_FUNCTION | 4 | 0 |
| COM_CREATE_PROCEDURE | 126 | 0 |
| COM_CREATE_TABLE | 354 | 0 |
| COM_DEALLOC_SQL | 924 | 0 |
| COM_DELETE | 64668 | 0 |
| COM_DELETE_MULTI | 19 | 0 |
| COM_DROP_FUNCTION | 4 | 0 |
| COM_DROP_PROCEDURE | 148 | 0 |
| COM_DROP_TABLE | 238 | 0 |
| COM_EXECUTE_SQL | 945 | 0 |
| COM_INSERT | 1182379 | 0 |
| COM_INSERT_SELECT | 40673 | 0 |
| COM_KILL | 68 | 0 |
| COM_LOAD | 22386 | 0 |
| COM_LOCK_TABLES | 2 | 0 |
| COM_OPTIMIZE | 2 | 0 |
| COM_PREPARE_SQL | 948 | 0 |
| COM_REPAIR | 8 | 0 |
| COM_REPLACE | 34737 | 0 |
| COM_ROLLBACK | 13 | 0 |
| COM_SELECT | 1107225018 | 65 |
| COM_SET_OPTION | 602159 | 0 |
| COM_SHOW_BINLOGS | 8 | 0 |
| COM_SHOW_CHARSETS | 12 | 0 |
| COM_SHOW_COLLATIONS | 100 | 0 |
| COM_SHOW_CREATE_DB | 6 | 0 |
| COM_SHOW_CREATE_FUNC | 2453 | 0 |
| COM_SHOW_CREATE_PROC | 5684 | 0 |
| COM_SHOW_CREATE_TABLE | 1313 | 0 |
| COM_SHOW_DATABASES | 275 | 0 |
| COM_SHOW_EVENTS | 1 | 0 |
| COM_SHOW_FIELDS | 13666 | 1 |
| COM_SHOW_FUNCTION_STATUS | 362 | 0 |
| COM_SHOW_KEYS | 494 | 0 |
| COM_SHOW_PLUGINS | 2 | 0 |
| COM_SHOW_PROCEDURE_STATUS | 361 | 0 |
| COM_SHOW_PROCESSLIST | 488943 | 15 |
| COM_SHOW_SLAVE_STATUS | 4 | 0 |
| COM_SHOW_STATUS | 12315 | 10 |
| COM_SHOW_STORAGE_ENGINES | 30 | 0 |
| COM_SHOW_TABLE_STATUS | 320 | 0 |
| COM_SHOW_TABLES | 584 | 0 |
| COM_SHOW_TRIGGERS | 2 | 0 |
| COM_SHOW_VARIABLES | 190 | 1 |
| COM_STMT_CLOSE | 924 | 0 |
| COM_STMT_EXECUTE | 945 | 0 |
| COM_STMT_PREPARE | 948 | 0 |
| COM_TRUNCATE | 522 | 0 |
| COM_UNLOCK_TABLES | 2 | 0 |
| COM_UPDATE | 496041 | 0 |
| COM_UPDATE_MULTI | 625 | 0 |
| CREATED_TMP_DISK_TABLES | 16772 | 40 |
| CREATED_TMP_TABLES | 34336 | 63 |
| HANDLER_COMMIT | 1109540769 | 0 |
| HANDLER_DELETE | 12775993 | 0 |
| HANDLER_EXTERNAL_LOCK | 2228108102 | 24 |
| HANDLER_PREPARE | 2155764 | 0 |
| HANDLER_READ_FIRST | 23586 | 9 |
| HANDLER_READ_KEY | 18285349400 | 0 |
| HANDLER_READ_LAST | 13000 | 0 |
| HANDLER_READ_NEXT | 72142303428 | 0 |
| HANDLER_READ_PREV | 3000146 | 0 |
| HANDLER_READ_RND | 1261418742 | 156 |
| HANDLER_READ_RND_NEXT | 12320861765 | 7845 |
| HANDLER_ROLLBACK | 269376 | 0 |
| HANDLER_UPDATE | 2596924399 | 0 |
| HANDLER_WRITE | 8200421074 | 8241 |
| LAST_QUERY_COST | 0.000000 | 21.399123 |
| LAST_QUERY_PARTIAL_PLANS | 0 | 3 |
| OPENED_TABLE_DEFINITIONS | 2482 | 0 |
| OPENED_TABLES | 3619 | 0 |
| QUESTIONS | 1110214247 | 97 |
| SELECT_FULL_JOIN | 615 | 9 |
| SELECT_RANGE | 243635 | 0 |
| SELECT_SCAN | 47851 | 53 |
| SLOW_QUERIES | 29290 | 50 |
| SORT_MERGE_PASSES | 6 | 0 |
| SORT_RANGE | 179956 | 0 |
| SORT_ROWS | 321609927 | 156 |
| SORT_SCAN | 1829 | 39 |
| TABLE_OPEN_CACHE_HITS | 1109365721 | 13 |
| TABLE_OPEN_CACHE_MISSES | 1669 | 0 |
+---------------------------+----------------+----------------+
90 rows in set (0.03 sec)
mysql>
Look at four variables:
| BYTES_RECEIVED | 123641576598 | 7757 |
| BYTES_SENT | 149888451047 | 300001 |
| COM_ADMIN_COMMANDS | 121915 | 0 |
| COM_SHOW_PROCESSLIST | 488955 | 15 |
What does this tell you?
- mysqld received 123,641,576,598 bytes (115.15GB) from all DB Connections since mysqld started
- The session I ran the query with received 7,757 bytes (a little over 7K) in my current session
- mysqld sent 149,888,451,047 bytes (139.59GB) from all DB Connections since mysqld started
- The session I ran the query with sent 300,001 bytes (a little under 297K) in my current session
- There have been 121,915 administrative commands that have run since mysqld started
- There have benn 0 administrative commands that have run in my current session
- The command
SHOW PROCESSLIST
has been run 488,955 times since mysqld started
- The command
SHOW PROCESSLIST
has been run 15 times in my current session
You can compare the other 86 varibales and interpret them the same way.
Give it a Try !!!
Best Answer
ANALYSIS
Look back at your question where you said
Here is the context right from the MySQL Documentation
Look at your numbers
Qcache_total_blocks
: 18381Qcache_free_blocks
: 4250Qcache_queries_in_cache
7027Given these numbers
On average, you can interpret this to mean one of the following:
Each individual block's fragmentation cannot be fixed. On the other hand, the query cache's total fragmentation can be adjusted by doing one thing the Documentation says (which I highlighted and italicized) :
decrease the value of query_cache_min_res_unit
.If you want more performance (as I had italicized),
you can increase performance by increasing query_cache_min_res_unit
. This will introduce more fragmentation and more query cache pruning.YOUR ACTUAL QUESTION
On average, Yes
Depends on what you want, more performance or less fragmentation.
With 23.12% fragmentation, I would work on decreasing query_cache_min_res_unit to lower the query cache's pruning activity against small queries. Strictly in terms of the query cache, performance will take care of itself. When you can drop the fragmentation percentage, you could possibly increase the query_cache_size to fit more query results IF AND ONLY IF the results are frequently accessed.
Think about this as well: each block is 1K since the Documentation says
Thus, 2.6K per query result. Again, this gives you more reason to focus on reducing fragmentation.
UPDATE 2014-10-28 12:53 EDT
I just remembered something that I needed to correct. The size of a block is not 1K. I believe that the size of a query cache block is actually set by query_alloc_block_size. If this is the case, then 2.6 blocks is not 2.6K as I thought before.
Given the default value for query_alloc_block_size is 8K, then 2.6 blocks would be 20.8K.
In light of this, let's look at the numbers again.
TOTAL BLOCKS
18381 (number of total blocks) X 8192 (8K default block size) rounded up
FREE BLOCKS
4250 (number of free blocks) X 8192 (8K default block size) rounded up
Simply subtraction shows that 110M is in use for the 7027 queries.
AVERAGE SPACE PER QUERY RESULT
That yields 16.03K per results.
BUT WAIT ...
Mathematically, we both figured out that 2.6 blocks per query was 20.8K. Since average space per query result (16.03K) is a few bytes above 2.0 blocks, fragmentation is all but guaranteed.
SUGGESTION
The Documentation says of query_alloc_block_size
Therefore, you should increase query_alloc_block_size to 16K, 24K or 32K. Try any multiple of 8K until the fragmentation is lower. Due this in conjunction with either increasing or decreasing query_cache_size.
GIVE IT A TRY !!!