MySQL query cache, complex SQL query
following problem is giving me a headache.
I have set up my MySQL server to use "Query Chaching".
set global query_cache_size = 10000000;
it seems that my query cache works because the output of
SHOW STATUS LIKE 'Qcache%';
is as follows
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 47223976 |
| Qcache_hits | 6709 |
| Qcache_inserts | 2314 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 365 |
| Qcache_queries_in_cache | 441 |
| Qcache_total_blocks | 960 |
+-------------------------+----------+
but, nevertheles the following (complex query, with inner selects etc.) doesn't get cached.
It alsways takes at least 0.8 secs to retrieve the data for this query. How can I bring mysql to store the results of this query in it's cache?
I tried ot remove the inner selects but this didn't make a differnence.
SELECT p.id
AS
project_id,
p.code
AS project_code,
p.title
AS project_title,
p.start_date
AS project_start_date,
p.end_date
AS project_end_date,
p.modf
AS project_modf,
( p.budget * (SELECT 1 / r.VALUE
FROM exchange_rates r
WHERE r.class_currency_id = p.class_budget_currency_id) )
AS
project_budget,
(SELECT z.txt
FROM sys_labels z
WHERE z.id = ps.value_label_id
AND z.lng = 'en')
AS project_status,
(SELECT z.txt
FROM sys_labels z
WHERE z.id = ps.data_label_id
AND z.lng = 'en')
AS project_color,
GROUP_CONCAT(DISTINCT pt.class_topic_id)
AS projects_thematic_area_ids,
u.id
AS project_owner_id
FROM projects AS p
LEFT JOIN projects_thematic_areas AS pt
ON pt.project_id = p.id
LEFT JOIN sys_users AS u
ON u.id = p.owner_uid
LEFT JOIN class_data s
ON s.id = p.class_status_id
LEFT JOIN class_data AS ps
ON ps.id = s.id
LEFT JOIN sys_labels AS prdz1
ON prdz1.id = prd.value_label_id
AND prdz1.lng = 'en'
LEFT JOIN sys_labels AS prdz2
ON prdz2.id = prd.data_label_id
AND prdz2.lng = 'en'
LEFT JOIN projects_locations AS pl
ON pl.project_id = p.id
LE开发者_如何学运维FT JOIN class_data AS l
ON l.id = pl.class_location_id
LEFT JOIN class_data AS r
ON r._lft <= l._lft
AND r._rgt >= l._rgt
AND r._level = 1
AND r.class_id = 5
LEFT JOIN class_data AS c
ON c._lft <= l._lft
AND c._rgt >= l._rgt
AND c._level = 2
AND c.class_id = 10
LEFT JOIN projects_donors AS pd
ON pd.project_id = p.id
LEFT JOIN institutions AS i
ON pd.inst_id = i.id
LEFT JOIN class_data AS ic
ON ic.id = i.class_country_id
LEFT JOIN projects_deliverables AS d
ON d.project_id = p.id
WHERE 1 = 1
AND p.is_del = "f"
AND p.is_active = "t"
GROUP BY p.id
ORDER BY p.modf DESC,
p.code DESC
Any help apprechiated ....
Regards
J.
In addition to previous answers: The query cache will not be used even if the query is in there if there are changes in any of the selected tables.
But why are you joining al those tables when you are not selecting anything from them? Also you probably shouldn't sub-select anything if you can join it.
Something like this would select exactly the same:
SELECT
p.id AS project_id,
p.code AS project_code,
p.title AS project_title,
p.start_date AS project_start_date,
p.end_date AS project_end_date,
p.modf AS project_modf,
p.budget * (1 / r.VALUE) AS project_budget,
z1.txt AS project_status,
z2.txt AS project_color,
GROUP_CONCAT(DISTINCT pt.class_topic_id) AS projects_thematic_area_ids,
u.id AS project_owner_id
FROM
projects AS p
LEFT JOIN projects_thematic_areas AS pt ON pt.project_id = p.id
LEFT JOIN sys_users AS u ON u.id = p.owner_uid
LEFT JOIN exchange_rates AS r ON r.class_currency_id = p.class_budget_currency_id
LEFT JOIN class_data s ON s.id = p.class_status_id
LEFT JOIN class_data AS ps ON ps.id = s.id
LEFT JOIN sys_labels AS z1 ON z1.id = ps.value_label_id AND z1.lng = 'en'
LEFT JOIN sys_labels AS z2 ON z2.id = ps.data_label_id AND z2.lng = 'en'
WHERE
1
AND p.is_del = "f"
AND p.is_active = "t"
GROUP BY
p.id
ORDER BY
p.modf DESC,
p.code DESC
Of course you have (combined) indexes on all foreign keys, where fields and group fields. Consider using a tinyint or enum field for your boolean values. You may also want to consider not selecting that GROUP_CONCAT so you can lose the GROUP BY. And perhaps using INNER JOIN instead of LEFT JOIN if you are certain the relation exists.
You may try SELECT SQL_CACHE ... FROM ...
A few basic things you can try:
- Read the Query Cache Documentation to make sure you understand the basics and have setup it correctly.
- Ideally isolate your MySQL database server so it is only running the commands you are giving it. If you cannot do this then try setting up and running tests on another machine.
- Run a simple query and look at the
Qcache_hits
andCom_select
status variables to determine whether the query cache is being hit or not. - Try your complex query and monitor the same values. If your query isn't hitting the cache then try smaller parts of it until you find out what is causing it to not get cached. If it is being cached then the issue may be due to any of the tables in the query being updated between queries which would invalidate the cached copy.
精彩评论