No MySQL, a ordem das colunas na cláusula WHERE afeta o desempenho da consulta?

38

Estou tendo problemas de desempenho em determinadas consultas ao banco de dados que possuem grandes conjuntos de resultados possíveis.

A consulta em questão, eu tenho três ANDs na cláusula WHERE

A ordem das cláusulas é importante?

Por exemplo, se eu colocar a cláusula ASI_EVENT_TIME em primeiro lugar (pois isso removeria a maioria dos resultados de qualquer uma das cláusulas.

Isso melhorará o tempo de execução na consulta?

INQUERIR:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

EXPLAIN da consulta:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

Usando:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5

Patrick
fonte
O ORDER BY provavelmente está demorando tanto. "Usar o filesort" pode ser extremamente lento. Eu descobri que fazer pedidos na lógica do aplicativo é muito mais rápido do que usar ORDER BY.
Maclema 22/03
Eu fiz essa mesma pergunta há um tempo (antes deste site) no stackoverflow. Verifique os links para obter respostas que recebi lá. stackoverflow.com/questions/3805863/…
Scott
2
@maclema - A menos que seu aplicativo esteja sendo executado em uma máquina muito mais rápida que seu banco de dados, sua afirmação é certamente falsa, sem mencionar a carga inútil de toda essa lógica de classificação em seu aplicativo. order bypertence ao banco de dados.
Jack Douglas

Respostas:

24

Eu penso que não. O otimizador de consulta deve ser inteligente o suficiente.

Você pode tentar reorganizar as cláusulas WHERE e ver que EXPLAINS diz o mesmo em cada caso.


Sobre o que pode ser feito para otimizar esta consulta: Existe um índice em ASI_EVENT_TIME? (acho que é o mais crucial para esta consulta, pois você também classifica os resultados usando-a).

Existem índices nos outros dois campos (ASI_SEISMO_ID e ASI_ACTIVITY_ID)?

Seria útil se você publicasse a estrutura da tabela.

ypercubeᵀᴹ
fonte
Eu nunca pensei em criar um índice dos horários dos eventos. Vou tentar isso amanhã em um dev db e ver se há alguma diferença perceptível.
Patrick
@Patrick Supondo que todas as outras consultas que usem esse índice estejam ordenando esta data em ordem decrescente, você também deseja ordenar a chave do índice (activity_seismo_info.ASI_EVENT_TIME) em ordem decrescente.
Matt M
@ MattM Eu não sabia que você poderia pedir uma chave de índice. Impressionante Se eu pedir a chave de índice, isso necessariamente prejudicará a ordem de desempenho na direção oposta ao ponto de ser pior do que nenhuma chave de índice?
22411 Patrick
@ Patrick Você está certo. Meu cérebro está preso na terra do SQL Server. Você pode especificar a ordem de classificação no MYSQL e ela será analisada, mas será ignorada. Todos os índices são classificados em ordem crescente no MYSQL. Desculpe pela confusão.
Matt M
13

A partir da documentação :

Se a tabela tiver um índice de várias colunas, qualquer prefixo mais à esquerda do índice poderá ser usado pelo otimizador para localizar linhas. Por exemplo, se você tiver um índice de três colunas em (col1, col2, col3), poderá indexar os recursos de pesquisa em (col1), (col1, col2) e (col1, col2, col3).

O MySQL não pode usar um índice se as colunas não formarem o prefixo mais à esquerda do índice.

Então, sim, deve ser igual à ordem das colunas em um índice composto .

Gaius
fonte
4
Se a tabela tiver um índice de várias colunas, a seleção de colunas da esquerda é importante - mas a ordem na qual você seleciona não importa. Portanto, se você tiver o índice a, b, c, WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'e o índice ainda estiver qualificado para uso.
Texelate
10

Não, isso não importa.

O otimizador faz várias transformações simples logo após analisar o SQL - este é um deles.

Morgan Tocker
fonte
8

ONDE foo e bar

otimiza o mesmo que

ONDE bar e foo

Contudo,

ONDE # 1 diferente e # 2 diferente

Não é possível otimizar ambas as partes. Por exemplo,

ONDE a ENTRE 1 e 3 eb> 17

não pode fazer bom uso de INDEX (a, b) ou INDEX (b, a)

Para expressá-lo de maneira diferente, todos os testes '=' AND 'juntos na cláusula WHERE são usados ​​primeiro, então um não -' = '(IN, BETWEEN,>, etc) pode ser tratado. Não mais que um pode ser efetivamente otimizado.

Sua consulta possui 3 cláusulas.

Como se vê, INDEX (EVENT_TIME) é provavelmente o mais útil - ele ajudará em um dos ANDs e pode ser usado para evitar "sortimento de arquivos" para o ORDER BY.

Se não houver linhas duplicadas (por que diabos haveria?), Livre-se do DISTINCT. Isso causa ainda mais esforço.

Forneça SHOW CREATE TABLE e SHOW TABLE STATUS ao fazer perguntas sobre desempenho.

Atualizar ... Versões mais recentes (por exemplo, MySQL 5.7) podem, em algumas situações, tratar IN( list of constants )quase como =. Para garantir a segurança, siga esta ordem (cada parte é opcional):

  1. Qualquer número de =.
  2. Alguns INs.
  3. No máximo um intervalo.
Rick James
fonte
1

MySQL, onde o documento de otimização diz:

Você pode se sentir tentado a reescrever suas consultas para acelerar as operações aritméticas, sacrificando a legibilidade. Como o MySQL faz otimizações semelhantes automaticamente , muitas vezes você pode evitar esse trabalho e deixar a consulta de uma forma mais compreensível e sustentável. Algumas das otimizações realizadas pelo MySQL:

  • ...

  • Para cada tabela em uma junção, um WHERE mais simples é construído para obter uma avaliação WHERE rápida da tabela e também para pular linhas o mais rápido possível .

  • Cada índice de tabela é consultado e o melhor índice é usado, a menos que o otimizador acredite que é mais eficiente usar uma verificação de tabela . Ao mesmo tempo, uma varredura foi usada com base em se o melhor índice abrangia mais de 30% da tabela, mas uma porcentagem fixa não determina mais a escolha entre usar um índice ou uma varredura. O otimizador agora é mais complexo e baseia sua estimativa em fatores adicionais, como tamanho da tabela, número de linhas e tamanho do bloco de E / S.

Dessa forma, é racional que o otimizador de consulta omita a ordem HOW, que usamos as colunas na consulta (não apenas o MySQL, mas o SQL é uma linguagem declarativa e deve fazer o que queremos, e não o que queremos).

No entanto, ainda gosto de ter a mesma classificação para as colunas de uma chave composta na consulta, mas às vezes é inevitável, por exemplo, quando usamos ORM ou ActiveRecord, em algumas estruturas como yii2, a personalização dos critérios de relação será anexada ao final de uma condição "on", mas ainda precisamos dos recursos do QueryBuilders em diferentes partes de um aplicativo.

Alix
fonte
-2

QUALQUER campo usado nas cláusulas WHERE / HAVING e com alta seletividade (o número de valores únicos / o número total de registros> 10% ~ 20%) DEVE ser indexado.

Portanto, se sua ASI_EVENT_TIMEcoluna tiver muitos valores possíveis, primeiro indexe todos eles. Então, como o @ypercube disse, tente reorganizá-los e veja o que EXPLAIN lhe diz. Deve ser o mesmo.

Além disso, você deve dar uma olhada em Indexar SQL LIKE Filters . Embora não seja para isso que você precisa de uma resposta, você ainda aprenderá como a indexação funciona sob o capô.

* Editar: consulte os links fornecidos abaixo nos comentários para saber mais sobre a indexação.

Olho
fonte
8
-1 A indexação de cada coluna NÃO é uma prática recomendada. Todo índice custa de várias maneiras. Escolha bons índices, que geralmente consistem em várias colunas, geralmente na ordem de seletividade e frequência usadas. Isso pode estar inclinado para o SQL Server, mas as informações do índice ainda são válidas: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - lotsahelp
@ Eric Humphrey +1 Para a explicação e o link para o site de Kimberly.
Matt M
você está errado, o índice na coluna às vezes prejudica seu desempenho em consultas selecionadas: mysqlperformanceblog.com/2007/08/28/… . Você nunca deve usar a regra de ouro: às vezes funciona, às vezes não.
sumar
Certo, eu concordo. No entanto, isso é válido caso a seletividade do valor seja baixa. Considerando o tipo de dados que Patrick (autor desta pergunta) usa, que é DATETIME, a indexação é recomendada. Geralmente esse tipo de campo tem um conjunto muito grande de valores, a menos que haja uma situação estranha quando ele usa apenas várias datas possíveis. * Editarei minha resposta acima para fazer uma declaração mais clara e válida.
do olho