“Copiando para a tabela tmp” extremamente lento

15

Este é o meu exemplo de consulta:

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;

Explique o que selecionar:

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

A criação de perfil dessa seleção me diz:

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

E algumas informações sobre variáveis ​​do 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

Por que a cópia na tabela tmp é tão lenta? Como melhorar a velocidade da minha consulta?

PS: Não consigo configurar o MySQL porque meu provedor de hospedagem não permite.

Gofrolist
fonte

Respostas:

22

Pode ser necessário tentar definir determinadas variáveis ​​na sua sessão

Esses valores específicos podem ser muito pequenos para a sua conexão com o banco de dados atender à consulta com eficiência. Eles podem ser definidos da seguinte maneira:

  • Para ver quais valores essas configurações atualmente fazem o seguinte:
    • SHOW VARIABLES LIKE 'max_heap_table_size';
    • SHOW VARIABLES LIKE 'tmp_table_size';
  • Para definir max_heap_table_size como 64M, faça o seguinte:
    • SET max_heap_table_size = 1024 * 1024 * 64;
  • Para definir tmp_table_size como 32M, faça o seguinte:
    • SET tmp_table_size = 1024 * 1024 * 32;

Por favor, consulte a documentação do MySQL sobre o uso da tabela temporária

Se você não pode definir esses valores em sua própria sessão, entre em contato com seu provedor de hospedagem para defini-los dinamicamente no my.cnf.

De uma chance !!!

RolandoMySQLDBA
fonte
+1 para definir as variáveis dentro da sessão, ele certamente pode ajudar a esta consulta, o que parece bastante complicado ...
Dave Rix
5

Você pode reduzir a consulta apenas àquelas tabelas absolutamente necessárias para produzir sua saída ou dividir a consulta em várias consultas separadas para extrair diferentes partes da informação?

Você pode descobrir que executar três consultas separadas em seus dados será mais rápido do que executar uma consulta grande - especialmente quando o banco de dados começar a aumentar para dezenas e centenas de milhares de linhas.

Também notei no meu próprio trabalho que as LEFT JOINconsultas não são necessariamente as mais eficientes; portanto, use-as apenas quando for absolutamente necessário ...

Espero que ajude :)

Dave Rix
fonte
11
Às vezes, consultas menores fazem mais sentido do que uma massa pesada de tabelas e LEFT JOINs (exemplo: stackoverflow.com/questions/5983156/… ) +1 !!!
RolandoMySQLDBA