Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Consulta lenta do MySQL:JOIN + multiple WHERES + ORDER BY


Índices fazem uma enorme diferença no mysql, uma consulta que levou 15 minutos com um conjunto errado de índices levou 0,2 segundos com os corretos, mas é encontrar o equilíbrio certo que geralmente é o problema. Naturalmente, sem alguns dados de amostra, é muito difícil dizer se a solução abaixo economizará tempo, mas em teoria deveria.

Para responder às suas perguntas, eu redesenharia as tabelas assim:
CREATE TABLE `product_all` ( 
`prod_id` INT( 10 ) NOT NULL, 
`ref_id` INT( 10) NOT NULL, 
`date` DATE NOT NULL , 
`buy_link` BLOB NOT NULL , 
`sale_price` FLOAT NOT NULL,
PRIMARY KEY (prod_id, ref_id) ,
INDEX date_Index (`date` ASC),
UNIQUE INDEX prod_price_Index (prod_id ASC, sale_price ASC)
) ENGINE = MYISAM ; 


CREATE TABLE `product_info` ( 
`prod_id` INT( 10 ) NOT NULL AUTO_INCREMENT, 
`prod_name` VARCHAR( 200 ) NOT NULL, 
`brand` VARCHAR( 50 ) NOT NULL, 
`retail_price` FLOAT NOT NULL, 
`category` INT( 3 ) NOT NULL, 
`gender` VARCHAR( 1 ) NOT NULL, 
`type` VARCHAR( 10 ) NOT NULL,
PRIMARY KEY (prod_id) ,
UNIQUE INDEX prod_id_name_Index (prod_id ASC, prod_name ASC),
INDEX category_Index (category ASC),
INDEX gender_Index (gender ASC)
) ENGINE = MYISAM ;

SELECT product_info.*, MIN(product_all.sale_price) as sale_price, product_all.buy_link         
FROM product_info         
NATURAL JOIN (SELECT * FROM product_all WHERE product_all.date = '2010-09-30') as product_all         
WHERE (product_info.category = 2           
AND product_info.gender = 'W' )         
GROUP BY product_all.prod_id         
ORDER BY MIN(product_all.sale_price) ASC LIMIT 13        

O ganho de desempenho aqui é obtido com a indexação dos principais campos que estão sendo unidos e são apresentados na cláusula where. Pessoalmente, eu iria com sua primeira consulta, pois quando você pensa sobre isso, deve ter um desempenho melhor.

Tanto quanto eu entendo o que está acontecendo na primeira e segunda consulta:
  • A primeira consulta está sendo filtrada por uma subconsulta antes de fazer a junção natural, o que significa que ela só une os dados resultantes e não a tabela inteira.
  • A segunda consulta está juntando toda a segunda tabela e, em seguida, filtrando as linhas resultantes de todo o lote de volta para o que você deseja.

Como regra geral, normalmente você deseja adicionar índices em seus principais campos de junção e também os campos que você mais usa nas cláusulas where. Também coloquei alguns índices exclusivos em alguns dos campos que você deseja consultar regularmente, como prod_id_name_Index.

Se isso não melhorar seu desempenho, se você puder postar alguns dados fictícios para brincar, talvez consiga uma solução mais rápida que possa comparar.

Aqui é um artigo que passa por indexação para desempenho no mysql, vale a pena ler se quiser saber mais.

Boa sorte!

EDIT:Sua pergunta final eu perdi da primeira vez, a resposta é que, se você indexar os principais campos de junção, mudar para onde só afetará ligeiramente o desempenho geral, mas os índices exclusivos que coloquei nas tabelas devem levar em conta o maioria das coisas nas quais você deseja basear as consultas. A principal coisa a ser lembrada é que se você consulta ou se junta a um campo com frequência, ele deve ser indexado, mas consultas menores e alterações na ordem por você não devem se preocupar em realinhar sua estratégia de indexação.