Eu tenho uma consulta que está sendo executada em mais de 15 segundos
SELECT
t1.`ST_StockCode`, t2.`SM_StockCode`, t2.`ST_ItemSize`
FROM
`stocks` AS t1,
`stocks` AS t2
WHERE
t1.`ST_StockCode` = t2.`SM_StockCode`
GROUP BY t1.`ST_StockCode`
ORDER BY t1.`id` ASC
Como posso reescrever/otimizar a consulta para acelerar o tempo de execução.
Estrutura da tabela
CREATE TABLE `stocks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ST_StockCode` int(11) NOT NULL,
`SM_StockCode` int(11) NOT NULL,
`ST_ItemSize` decimal(18,2) DEFAULT '0.00',
PRIMARY KEY (`id`),
KEY `stockcode` (`ST_StockCode`),
KEY `sm_stockcode` (`SM_StockCode`)
) ENGINE=InnoDB
EXPLICAR O PLANO
+----+-------------+-------+------+--------------------+-----------+---------+--------------------+---------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+--------------------+-----------+---------+--------------------+---------+---------------------------------+
| 1 | SIMPLE | t2 | ALL | sm_stockcode | NULL | NULL | NULL | 1000545 | Using temporary; Using filesort |
| 1 | SIMPLE | t1 | ref | stockcode,idx_test | stockcode | 4 | lc.t2.SM_StockCode | 4 | Using index |
+----+-------------+-------+------+--------------------+-----------+---------+--------------------+---------+---------------------------------+
ATUALIZE ALGUMAS LINHAS
SELECT * FROM stocks LIMIT 10;
+----+--------------+--------------+-------------+
| id | ST_StockCode | SM_StockCode | ST_ItemSize |
+----+--------------+--------------+-------------+
| 1 | 679783 | 678649 | 7.00 |
| 2 | 679789 | 688622 | 7.00 |
| 3 | 679792 | 679793 | 8.00 |
| 4 | 679792 | 686376 | 8.00 |
| 5 | 679793 | 679792 | 7.00 |
| 6 | 679793 | 686376 | 8.00 |
| 7 | 679795 | 679796 | 8.00 |
| 8 | 679796 | 679795 | 7.00 |
| 9 | 679797 | 617114 | 7.00 |
| 10 | 679797 | 627339 | 7.00 |
+----+--------------+--------------+-------------+
PARA ypercubo
SELECT * FROM similar_stocks WHERE ST_StockCode = 679792 OR SM_StockCode = 679792 ;
+-------+--------------+--------------+-------------+
| id | ST_StockCode | SM_StockCode | ST_ItemSize |
+-------+--------------+--------------+-------------+
| 3 | 679792 | 679793 | 8.00 |
| 4 | 679792 | 686376 | 8.00 |
| 5 | 679793 | 679792 | 7.00 |
| 4774 | 686376 | 679792 | 7.00 |
| 50028 | 679792 | 679793 | 8.00 |
| 50029 | 679792 | 686376 | 8.00 |
| 50030 | 679793 | 679792 | 7.00 |
| 52798 | 686376 | 679792 | 7.00 |
+-------+--------------+--------------+-------------+
Vamos começar dissecando a consulta original, com base nos dados de exemplo fornecidos:
SQL Fiddle
Configuração do esquema do MySQL 5.5.32 :
Consulta 1 :
Resultados :
A primeira coisa a observar é que, sendo uma junção interna, os dois valores ST_StockCode e SM_StockCode são sempre idênticos. Nos exemplos a seguir, menciono apenas um deles, pois é fácil adicionar o que falta.
Em segundo lugar, esta consulta está usando uma extensão não SQL Standard para a cláusula GROUP BY. A consulta é agrupada por ST_StockCode e, em seguida, faz referência a duas outras colunas sem uma agregação. O MySQL retornará para essas colunas o primeiro valor que encontrar. Ele não verifica se os valores são distintos e você pode obter resultados diferentes a cada execução. Se assumirmos que o criador da consulta original estava ciente desse comportamento, podemos fazer isso:
Consulta 2 :
Resultados :
Isso retorna para cada SM_StockCode o ST_ItemSize mínimo (em vez de aleatório). No entanto, ele retorna potencialmente mais linhas do que a consulta original porque pode haver SM_StockCodes que não possuem um ST_StockCode correspondente (como nos dados de exemplo fornecidos). No entanto, isso é facilmente corrigido:
Consulta 3 :
Resultados :
Agora, apenas SM_StockCodes que possuem um ST_StockCodes correspondente são retornados. (Você precisa duplicar a coluna SM_StockCode se realmente precisar desse valor duas vezes.)
Com a consulta escrita desta forma, a estratégia de indexação torna-se bastante óbvia:
Crie um índice em ST_StockCode para suportar a pesquisa EXISTS e crie um segundo índice em SM_StockCode, ST_ItemSize para suportar GROUP BY.
Se você tem certeza de que cada SM_StockCode tem um ST_StockCode correspondente (por exemplo, porque uma chave estrangeira foi declarada entre os dois ou porque dois dos analistas juram que esse é sempre o caso), você pode encurtar ainda mais a consulta:
Consulta 4 :
Resultados :
No entanto, como no exemplo de trecho de dados de 10 linhas aleatórias, essa condição não é fornecida, o resultado acima não corresponde a esse caso.