cache de requêtes MySQL, requête SQL complexe
-
25-09-2019 - |
Question
problème suivant me donne un mal de tête.
J'ai mis mon serveur MySQL pour utiliser "Requête Chaching".
set global query_cache_size = 10000000;
il semble que mon cache de requête fonctionne parce que la sortie de
SHOW STATUS LIKE 'Qcache%';
est comme suit
+-------------------------+----------+
| 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 |
+-------------------------+----------+
mais, nevertheles les éléments suivants (requête complexe, avec intérieur etc.) sélectionne ne pas mises en cache.
Il faut alsways au moins 0,8 secs pour récupérer les données de cette requête. Comment puis-je apporter mysql stocker les résultats de cette requête dans son cache ?
J'ai essayé ot enlever Selects intérieur mais cela ne rendait pas un 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
LEFT 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
Toute aide apprechiated ....
Cordialement
J.
La solution
En plus des réponses précédentes. Le cache de requête ne sera pas utilisée même si la requête est là-dedans s'il y a des changements dans l'une des tables sélectionnées
Mais pourquoi êtes-vous joindrez al ces tables lorsque vous ne sélectionnez rien d'eux? Aussi, vous ne devriez probablement pas sous-sélectionner quelque chose si vous pouvez le joindre.
Quelque chose comme ceci choisirait exactement le même:
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
Bien sûr, vous avez des index (combinés) sur toutes les clés étrangères, où les champs et les champs de groupe. Pensez à utiliser un tinyint ou champ ENUM pour vos valeurs booléennes. Vous pouvez également envisager de ne pas sélectionner que GROUP_CONCAT de sorte que vous pouvez perdre le GROUP BY. Et peut-être en utilisant INNER JOIN au lieu de LEFT JOIN si vous êtes certain de la relation existe.
Autres conseils
Vous pouvez essayer SELECT SQL_CACHE ... FROM ...
Quelques choses de base que vous pouvez essayer:
- Lire la cache de requêtes Documentation pour vous assurer vous comprenez les bases et ont la configuration correctement.
- isoler votre serveur idéal de base de données MySQL de sorte qu'il ne fonctionne que les commandes que vous lui donnez. Si vous ne pouvez pas le faire, puis mettre en place et l'exécution des tests sur une autre machine.
- Exécuter une requête simple et regarder les variables d'état et de
Qcache_hits
Com_select
pour déterminer si le cache de requête est frappé ou non. - Essayez votre requête complexe et surveiller les mêmes valeurs. Si votre requête ne frappe pas le cache essayez de parties plus petites jusqu'à ce que vous trouverez ce qui est à l'origine de ne pas se cache. Si elle est mise en mémoire cache alors le problème peut être dû à l'une des tables de la requête étant mise à jour entre les requêtes, ce qui invaliderait la copie en cache.