EmergencyEMERGENCY? Get 24/7 Help Now!

The MySQL Query Cache: How it works, plus workload impacts (good and bad)

 | January 2, 2015 |  Posted In: MySQL, Percona Server for MySQL


The MySQL query cache is one of the prominent features in MySQL and a vital part of query optimization. It is important to know how the MySQL query cache works, as it has the potential to cause significant performance improvements – or a slowdown – of your workload.

The MySQL query cache is a global one shared among the sessions. It caches the select query along with the result set, which enables the identical selects to execute faster as the data fetches from the in memory. It is important to have everything identical, no new comments, spaces, or most significantly differences in the WHERE clause. Basically when you trigger a select query, if it is available in the cache; it fetches from there or it considers the query as a new one and will go to the parser.

Even though it has some nice advantages, the MySQL query cache has its own downsides too. Well, let’s think about this: If you are frequently updating the table, you are then invalidating the query cache for ALL queries cached for that table. So really, anytime you have a “frequently updated table” means you’re probably not going to get any sort of good usage from the MySQL query cache. See the below example.

From the above  we are sure the queries are cached. Let us try an insert and see the status, it will invalidate the query cache and reclaim the memory.

Now let us think about how to decide the MySQL query cache size:

To exemplify:  I am having a mysql instance with two tables “t” and “t1”. Table “t” is with numerous records and “t1” is with a fewer records. Let’s restart the mysql and see the query cache details.

From the above status note the below four points.

1) There is around 1 MB free space with Qcache.

2) The queries in Qcache are zero.

3) There is no Qcache hits.

4) Qcache lowmem prunes is zero.

From the aforesaid status it is clear the query has been cached and it should execute much faster in the next try and increase the Qcache hits status variable by one.

Now let us see how the data is getting pruned from the Qcache. For this I will execute a select on table “t” which is having massive records.

The Qcache_lowmem_prunes is the status variable which indicates how many times MySQL had to clear/prune some data from the Qcache to make space for the outputs of other queries. We need to observe the Qcache_lowmem_prunes  status variable and try to increase/adjust the size of the cache till we get a very low value ratio for the variable.

It is also undesirable to keep the query cache relatively high value at 256 MB as the Qcache invalidation becomes costly. For details, Peter Zaitsev wrote about this a few years ago in a post that’s still relevant today titled, “Beware large Query_Cache sizes.”

Contention often makes the MySQL query cache the bottleneck instead of help when you have many CPU cores. Generally, the MySQL query cache should be off unless proven useful for your workload. So it is important to know your environment well to enable the MySQL query cache and to decide what the query cache size should be.

There will also be circumstances where there is no chance of identical selects and in this case it is important to set the query_cache_size and query_cache_type variable to zero. The query_cache_type variable controls the query cache and  setting the query_cache_type to zero will reduce the significant overhead in query execution. On a highly concurrent environment there are chances of query cache mutex, which may become the source of a bottleneck. Setting the query_cache_type to zero will avoid the query cache mutex, as the query cache cannot be enabled at runtime which reduces the overhead in query execution. Please go through the details of QUERY CACHE ENHANCEMENTS with Percona Server.

Hopefully this blog helped to explain how the MySQL query cache operates.

Arunjith Aravindan

Arunjith Aravindan is on Percona's consulting team and has several years experience in MySQL database and Linux administration at companies that include Amrita Technologies in addition to large U.S.-based travel technology firms. His main interests are databases and operating systems, specifically technologies like MySQL, Linux and Shell scripting. His specialities include installations, configurations, replication, backups, restores, log analysis, shell scripts, cron jobs, query analysis and crash recovery of databases (and much more).


  • Hi Arunjith,

    Thanks for explaining the “qcache_lowmem_prunes” so clearly and concisely.

    The post by Peter that a large query cache can cause serious performance issues is valid only when you have a query invalidating a large set of queries (we’re talking 10s of thousands of queries being invalidated). For most sites (especially non-transactional sites), this is not the case.

    Also, would it be possible to give a brief explanation on what a free block is and how it works?

  • Hi Fadi,
    The free blocks are the number of non-contiguous free memory blocks available in the query cache. Initially the query cache will be long and contiguous. Over time and with use, the long contiguous regions become fragmented into smaller and smaller contiguous areas.
    To better utilize the memory you can defragment the query cache with help of FLUSH QUERY CACHE statement. Basically the FLUSH QUERY CACHE does not empty the query cache but it defragments the query cache and the value for the Qcache_free_blocks becomes ‘1’.

  • Nice Article !
    I have also worked around this MySQL Query Cache and created my note in this blog:
    please visit some of my view about MySQL Query Cache.
    For basic theory :
    For basic configuration:

  • I have a column in my table which keeps on changing very frequently .How should i implement caching on that particular table ,should i move this column to different table ? How should i avoid caching invalidation ?

Leave a Reply