10

I am having a lot of troubles with the query cache on a project: I am running a Percona flavor of MySQL, same versions both on my local development machine as on the production server. Now, enabling the query cache gives me excellent results on my local machine: almost all queries that should be cached, effectively are.

Now, exactly the same queries are not being cached on the production server. Everything is exactly the same; the mysql variables, the database contents, the codebase, the logged in user, .. but on production only a handful queries are being cached, the most important ones are all being skipped. And I can't figure out why :-)

So, looking for a solution, I am working with the following query, used to select the latest 3 topics from the topics table: (this is the most "heavy" query and is the one I definitely want to be cached!)

SELECT `topic`.* FROM `topics` AS `topic` 
LEFT OUTER  JOIN `topics` AS `topic_helper` 
 ON (`topic`.`id` = `topic_helper`.`id` 
      AND `topic_helper`.`created_on` < `topic`.`created_on`) 
GROUP BY `topic`.`id` HAVING COUNT(*) < 3 
ORDER BY `topic`.`created_on` DESC;

So, to start, the SHOW VARIABLES LIKE '%query_cache% give me the same results, both local as on production:

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| have_query_cache             | YES      |
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 10485760 |
| query_cache_strip_comments   | OFF      |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+

Running the above query gets cached locally after the first run, as SHOW PROFILE clearly tells me near the end of it's trace:

| Waiting for query cache lock   | 0.000001 |
| Waiting on query cache mutex   | 0.000001 |
| freeing items                  | 0.000000 |
| storing result in query cache  | 0.000002 |
| logging slow query             | 0.000001 |
| cleaning up                    | 0.000006 |
+--------------------------------+----------+

Second call returns the query from the cache, as expected.

On the production server, running this query will never store it in the cache. The result set is exactly the same, and there are clearly no statements being used that would invalidate query caching (according to the manual at http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html - I am certain the above query does comply with the requirements for it to be cached.)

For completeness sake, the full output of the SHOW PROFILE for that same query on the production server, is pasted here: http://pastebin.com/7Jm5rmVd

Also, it is worth noting that although configuration is exactly the same on both servers, my local version is 5.5.27, slightly newer than the one on production 5.5.17-55. Could it be that this is the problem .. ?

I compared the full SHOW VARIABLES; output from both my local server as production server to see if anything was missing, but nothing differs except for the system time zone and the path's to log files etc ..

So, might any of you know where to look for next? Or have any clue what could be causing this?

Matthew
  • 9,851
  • 4
  • 46
  • 77
Steven Rombauts
  • 333
  • 1
  • 8
  • 4
    From your link to the MySQL manual, I just learnt that "A query also is not cached [if] the user has a column-level privilege for any of the involved tables". Could it be the case on your production server? Also, "any insert, update, delete, or other modification to a table causes any relevant entries in the query cache to be flushed.", http://dev.mysql.com/doc/refman/5.5/en/query-cache.html). This is likely to happen more often in production than on the test server. You may want to run your test in production during a low traffic time. – RandomSeed Dec 19 '12 at 10:41
  • Hi YaK, thank you for your insight. Just for testing, I quickly changed my db user to root, which should have no privileges withheld. The query cache is still not inserting the query, unfortunately. Also, I am working on the staging server (which is ofcourse an exact clone of production), so I am pretty sure there's not much traffic when I am testing :-) Thanks a lot for your help! – Steven Rombauts Dec 20 '12 at 15:04
  • 1
    A query is not cached if it have a non deterministic value.I don't know if count will count as non deterministic, try removing the count and test if it get's cached – FabioCosta Jan 13 '13 at 17:44
  • Nit (slight contradiction in question): "*I am running a Percona flavor of MySQL, same versions both on my local development machine as on the production server.*" and "*my local version is 5.5.27, slightly newer than the one on production 5.5.17-55*" – eggyal Jan 20 '13 at 10:36
  • 3
    Please include output of `SHOW STATUS LIKE 'Qcache%';` and `SHOW CREATE TABLE topics;` and also confirm that the query is not generating any warnings on the production server with `SHOW WARNINGS;` after the query has completed. – eggyal Jan 20 '13 at 10:43
  • show topic structure. If this table has fields like count_views, count_likes etc ... probably caching this table useless, reason - read first comment – san4o Mar 14 '13 at 09:32

1 Answers1

1

We use Percona server a lot here, and community MySQL too.

The query caches are powerful - and mightily complicated. The worse thing MySQL could do is return some stale cache data.

Not only does MySQL cache the queries, but also the database data too - and uses indexes for additional performance.

Anything which might invalidate the query cache, invalidates it.

As a rule of thumb - we don't focus too closely on whether it's being cached or not ... we trust that MySQL acts intelligently - if for any reason it thinks something shouldn't be cached, it doesn't cache it. What we do do though - is make sure our queries are as efficient and simple as possible.

If I may say this - I think you're going to hit serious scalability problems irrespective of the query cache if your example query is "one of your most used". It's going to run like a dog without legs once that server gets busy!

According to your pastebin entry - you've at least one temporary table being created, probably due to the outer join (or the GROUP BYs).

I'm all for normalisation - but sometimes performance demands an alternative route.

Can you not cache some of that data yourself, in a some sort of lookup/summary table? Triggers can be your friend here :)

wally
  • 3,492
  • 25
  • 31
  • As we fixed this problem I lost track of this topic, didn't receive notifications. Sorry about that. In the end we did solve it by refactoring our application logic and just making the queries simpler. As you said, that query was a problem waiting to happen - and we didn't even need it in the end. Keeping things simple was key here. – Steven Rombauts Apr 06 '15 at 13:03