2010-12-09 8 views
0

problème suivant me donne un mal de tête.MySQL requête cache, requête SQL complexe

J'ai configuré mon serveur MySQL pour utiliser "Query 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 la suivante

+-------------------------+----------+  
| 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 sélectionne interne, etc.) ne se cache pas.

Il faut toujours au moins 0,8 secondes pour récupérer les données pour cette requête. Comment puis-je amener mysql à stocker les résultats de cette requête dans son cache?

J'ai essayé d'enlever les sélections internes mais cela n'a pas fait de différence.

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.

Répondre

1

Outre les réponses précédentes: Le cache de requête ne sera pas utilisé même si la requête est là s'il y a des changements dans l'une des tables sélectionnées.

Mais pourquoi joignez-vous à toutes ces tables lorsque vous ne sélectionnez rien d'elles? Aussi, vous ne devriez probablement pas sous-sélectionner quoi que ce soit si vous pouvez le rejoindre.

Quelque chose comme cela choisirait exactement la 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 champ tinyint ou enum pour vos valeurs booléennes. Vous pouvez également envisager de ne pas sélectionner GROUP_CONCAT pour perdre le GROUP BY. Et peut-être utiliser INNER JOIN au lieu de LEFT JOIN si vous êtes certain que la relation existe.

0

Vous pouvez essayer SELECT SQL_CACHE ... FROM ...

0

Quelques choses de base que vous pouvez essayer:

  • Lire la Query Cache Documentation pour vous assurer que vous comprenez les bases et ont la configuration correctement.
  • Idéalement, isolez votre serveur de base de données MySQL afin qu'il exécute uniquement les commandes que vous lui donnez. Si vous ne pouvez pas le faire, essayez d'installer et d'exécuter des tests sur une autre machine.
  • Exécutez une requête simple et examinez les variables d'état Qcache_hits et Com_select pour déterminer si le cache de requête est en cours d'exécution ou non.
  • Essayez votre requête complexe et surveillez les mêmes valeurs. Si votre requête n'atteint pas le cache, essayez-en des parties plus petites jusqu'à ce que vous découvriez ce qui ne l'a pas mis en cache.Si elle est mise en cache, le problème peut être dû à l'une des tables de la requête en cours de mise à jour entre les requêtes qui invaliderait la copie mise en cache.