«Copie vers la table tmp» extrêmement lente


15

Voici mon exemple de requête:

SELECT
    nickname, 
    CASE class_id
      WHEN 1 THEN 'Druid'
      WHEN 2 THEN 'Necromancer'
      WHEN 3 THEN 'Mage'
      WHEN 4 THEN 'Priest'
      WHEN 5 THEN 'Warrior'
      WHEN 6 THEN 'Stalker'
      WHEN 7 THEN 'Paladin'
      WHEN 8 THEN 'Psionic'
    END class_name,
    ROUND(AVG(level),2) level,
    ROUND(AVG(tabard_id),2) tabard,
    CASE rank_id
      WHEN 1 THEN 'Leader'
      WHEN 2 THEN 'Officer'
      WHEN 3 THEN 'Veteran'
      WHEN 4 THEN 'HonoryMember'
      WHEN 5 THEN 'OrdinaryMember'
      WHEN 6 THEN 'Alt'
      WHEN 7 THEN 'Apprentice'
      WHEN 8 THEN 'Penalty'
    END rank_name,
    ROUND(AVG(loyality),2) loyality,
    ROUND((MAX(authority)-MIN(authority))/AVG(tabard_id)) authority_effective,
    MAX(authority)-MIN(authority) authority_delta,
    MIN(authority) authority_begin,
    MAX(authority) authority_end
FROM users
    LEFT JOIN level_history ON level_history.users_id = users.id
    LEFT JOIN tabard_history ON tabard_history.users_id = users.id
    LEFT JOIN rank_history ON rank_history.users_id = users.id
    LEFT JOIN loyality_history ON loyality_history.users_id = users.id
    LEFT JOIN authority_history ON authority_history.users_id = users.id
    LEFT JOIN guilds_has_users ON guilds_has_users.users_id = users.id
    LEFT JOIN report ON report.id = authority_history.report_id
      AND report.id = level_history.report_id
      AND report.id = loyality_history.report_id
      AND report.id = rank_history.report_id
      AND report.id = tabard_history.report_id
WHERE report.date BETWEEN '2011-10-24 00:00:00' AND '2011-10-30 23:59:59'
  AND guilds_has_users.active = 1
GROUP BY users.id;

Expliquez ce choix:

id  select_type   table               type    possible_keys                                            key                          key_len   ref                                           rows    Extra
1   SIMPLE        guilds_has_users    ref     fk_guilds_has_users_users1,active_IDX                    active_IDX                   1         const                                         139     Using where; Using temporary; Using filesort
1   SIMPLE        users               eq_ref  PRIMARY                                                  PRIMARY                      4         z92985_orlandino.guilds_has_users.users_id    1    
1   SIMPLE        level_history       ref     fk_level_history_users1,fk_level_history_report1,u...    fk_level_history_users1      4         z92985_orlandino.guilds_has_users.users_id    1       Using where
1   SIMPLE        report              eq_ref  PRIMARY,date_IDX,id_date_IDX                             PRIMARY                      4         z92985_orlandino.level_history.report_id      1       Using where
1   SIMPLE        tabard_history      ref     fk_tabard_history_users1,fk_tabard_history_report1...    fk_tabard_history_users1     4         z92985_orlandino.level_history.users_id       1       Using where
1   SIMPLE        rank_history        ref     fk_rank_history_users1,fk_rank_history_report1,use...    fk_rank_history_users1       4         z92985_orlandino.users.id                     1       Using where
1   SIMPLE        loyality_history    ref     fk_loyality_history_users1,fk_loyality_history_rep...    fk_loyality_history_users1   4         z92985_orlandino.rank_history.users_id        1       Using where
1   SIMPLE        authority_history   ref     fk_authority_history_users1,fk_authority_history_r...    fk_authority_history_users1  4         z92985_orlandino.level_history.users_id       1       Using where

Le profilage de cette sélection me dit:

(139 total, Query took 4.4918 sec)
Copying to tmp table 4.488318

Et quelques informations sur les variables MySQL:

SHOW VARIABLES LIKE '%buffer%';

Variable_name              Value
bulk_insert_buffer_size    8388608
join_buffer_size           131072
key_buffer_size            12884901888
myisam_sort_buffer_size    8388608
net_buffer_length          16384
preload_buffer_size        32768
read_buffer_size           131072
read_rnd_buffer_size       25165824
sort_buffer_size           2097144
sql_buffer_result          OFF

Pourquoi la copie vers la table tmp est-elle si lente? Comment améliorer la vitesse de ma requête?

PS: je ne peux pas configurer MySQL car mon hébergeur ne le permettra pas.

Réponses:


22

Vous devrez peut-être essayer de définir certaines variables dans votre session

Ces valeurs particulières peuvent être trop petites pour que votre connexion DB puisse répondre efficacement à la requête. Ceux-ci peuvent être définis comme suit:

  • Pour voir quelles valeurs ces paramètres ont actuellement, procédez comme suit:
    • SHOW VARIABLES LIKE 'max_heap_table_size';
    • SHOW VARIABLES LIKE 'tmp_table_size';
  • Pour définir max_heap_table_size sur 64M, procédez comme suit:
    • SET max_heap_table_size = 1024 * 1024 * 64;
  • Pour définir tmp_table_size sur 32M, procédez comme suit:
    • SET tmp_table_size = 1024 * 1024 * 32;

Veuillez consulter la documentation MySQL sur l'utilisation des tables temporaires

Si vous ne pouvez pas définir ces valeurs dans votre propre session, contactez votre hébergeur pour les définir dynamiquement dans votre my.cnf.

Essaie !!!


+1 pour définir les variables dans la session, cela peut certainement aider cette requête, qui semble plutôt compliquée ...
Dave Rix

5

Pouvez-vous éventuellement réduire la requête aux seules tables absolument nécessaires pour produire votre sortie, ou diviser la requête en plusieurs requêtes distinctes pour extraire différentes parties des informations?

Vous constaterez peut-être que l'exécution de trois requêtes distinctes sur vos données sera plus rapide que l'exécution d'une énorme - en particulier lorsque votre base de données commence à atteindre des dizaines et des centaines de milliers de lignes.

J'ai également remarqué de mon propre travail que les LEFT JOINrequêtes ne sont pas nécessairement les plus efficaces, donc ne les utilisez que lorsque cela est absolument nécessaire ...

J'espère que cela pourra aider :)


1
Parfois, des requêtes plus petites ont plus de sens qu'une masse de tables et de jointures à gauche (exemple: stackoverflow.com/questions/5983156/… ) +1 !!!
RolandoMySQLDBA
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.