2014-04-15 56 views
0

这个SQL查询正在花费230.63秒(差不多4分钟!)。由于嵌套SELECT,极慢的SQL查询。我该如何提高速度?

SELECT SQL_CALC_FOUND_ROWS vino.ID, detalle, nombre, do, vino.ID_do, anada, 
tamano_texto, vino.ID_tamano, precio, imagen_principal, vino.ID_imagen_principal, 
imagen_principal_tn, imagen_detalle, vino.ID_imagen_detalle, imagen_detalle_tn, 
vino.ID_tipo, tipo_texto, vino.ID_pais, pais_texto, precio_copa, precio_tienda FROM vino 
INNER JOIN almacen ON almacen.ID_categoria = 1 AND ID_articulo = vino.ID AND unidades > 0 
LEFT OUTER JOIN vino_componente ON vino_componente.ID_vino = vino.ID 
LEFT OUTER JOIN componente_texto ON componente_texto.ID_componente = vino_componente.ID_componente AND componente_texto.ID_idioma = 1 
LEFT OUTER JOIN do ON vino.ID_do = do.ID 
LEFT OUTER JOIN tamano ON vino.ID_tamano = tamano.ID 
LEFT OUTER JOIN tamano_texto ON tamano_texto.ID_tamano = tamano.ID AND tamano_texto.ID_idioma = 1 
LEFT OUTER JOIN imagen_principal ON vino.ID_imagen_principal = imagen_principal.ID 
LEFT OUTER JOIN imagen_detalle ON vino.ID_imagen_detalle = imagen_detalle.ID 
LEFT OUTER JOIN tipo ON vino.ID_tipo = tipo.ID 
LEFT OUTER JOIN tipo_texto ON tipo_texto.ID_tipo = tipo.ID AND tipo_texto.ID_idioma = 1 
LEFT OUTER JOIN pais ON vino.ID_pais = pais.ID 
LEFT OUTER JOIN pais_texto ON pais_texto.ID_pais = pais.ID AND pais_texto.ID_idioma = 1 
WHERE activo = 1 AND (
    nombre LIKE "%blanco%" 
    OR do LIKE "%blanco%" 
    OR vino.ID IN (
     SELECT ID_vino FROM vino_componente 
     WHERE componente_texto LIKE "%blanco%" 
    ) 
    OR anada LIKE "%blanco%" 
    OR tamano_texto LIKE "%blanco%" 
) 
ORDER BY tipo.orden_papel, vino.ID_pais, do, precio LIMIT 30; 

这是EXPLAIN:

id select_type   table    type   possible_keys key  key_len ref       rows Extra 
1 PRIMARY    almacen    ALL    NULL   NULL NULL NULL      3583 Using where; Using temporary; Using filesort 
1 PRIMARY    vino    eq_ref   PRIMARY   PRIMARY 4  almacen.ID_articulo   1  Using where 
1 PRIMARY    vino_componente  ALL    NULL   NULL NULL NULL      6101  
1 PRIMARY    componente_texto ALL    NULL   NULL NULL NULL      1103  
1 PRIMARY    do     eq_ref   PRIMARY   PRIMARY 4  vino.ID_do     1 
1 PRIMARY    tamano    eq_ref   PRIMARY   PRIMARY 4  vino.ID_tamano    1  Using index 
1 PRIMARY    tamano_texto  ALL    NULL   NULL NULL NULL      95  Using where 
1 PRIMARY    imagen_principal eq_ref   PRIMARY   PRIMARY 4  vino.ID_imagen_principal 1 
1 PRIMARY    imagen_detalle  eq_ref   PRIMARY   PRIMARY 4  vino.ID_imagen_detalle  1 
1 PRIMARY    tipo    eq_ref   PRIMARY   PRIMARY 4  vino.ID_tipo    1 
1 PRIMARY    tipo_texto   ref    ID_tipo   ID_tipo 5  tipo.ID      2 
1 PRIMARY    pais    eq_ref   PRIMARY   PRIMARY 4  vino.ID_pais    1  Using index 
1 PRIMARY    pais_texto   ALL    NULL   NULL NULL NULL      553 
2 DEPENDENT SUBQUERY vino_componente  ALL    NULL   NULL NULL NULL      6101 Using where 

如果我从WHERE子句中删除嵌套的“IN(SELECT)”,它就会降到一个较为合理的8秒,这仍然是相当缓慢,但并不那么慢。

那么为什么这个工作如此缓慢,我该如何改进以获得更好的速度?

+0

尝试删除JOIN子句。 – witherwind

+1

删除JOIN子句将导致不同的数据/逻辑。你不能只是这么做。 –

+0

我知道。他在问他如何加快速度。我刚刚给了一个答案。 – witherwind

回答

0

嗯,我终于找到了一种使用GROUP_CONCAT,GROUP BY和HAVING的组合来加快速度的方法,以取代执行数千次(每个记录一次)的嵌套SELECT。

现在查询仍然不快(运行需要10秒),但速度并不是非常慢(之前花了差不多4分钟),所以它仍然是一个非常大的改进!

SELECT SQL_CALC_FOUND_ROWS vino.ID, detalle, nombre, do, vino.ID_do, anada, tamano_texto, vino.ID_tamano, precio, imagen_principal, vino.ID_imagen_principal, imagen_principal_tn, imagen_detalle, vino.ID_imagen_detalle, imagen_detalle_tn, vino.ID_tipo, tipo_texto, vino.ID_pais, pais_texto, precio_copa, precio_tienda, 
GROUP_CONCAT(componente_texto) AS csv_componente_texto 
FROM vino 
INNER JOIN almacen ON almacen.ID_categoria = 1 AND ID_articulo = vino.ID AND unidades > 0 
LEFT OUTER JOIN vino_componente ON vino_componente.ID_vino = vino.ID 
LEFT OUTER JOIN componente_texto ON componente_texto.ID_componente = vino_componente.ID_componente AND componente_texto.ID_idioma = 1 
LEFT OUTER JOIN do ON vino.ID_do = do.ID 
LEFT OUTER JOIN tamano ON vino.ID_tamano = tamano.ID 
LEFT OUTER JOIN tamano_texto ON tamano_texto.ID_tamano = tamano.ID AND tamano_texto.ID_idioma = 1 
LEFT OUTER JOIN imagen_principal ON vino.ID_imagen_principal = imagen_principal.ID 
LEFT OUTER JOIN imagen_detalle ON vino.ID_imagen_detalle = imagen_detalle.ID 
LEFT OUTER JOIN tipo ON vino.ID_tipo = tipo.ID 
LEFT OUTER JOIN tipo_texto ON tipo_texto.ID_tipo = tipo.ID AND tipo_texto.ID_idioma = 1 
LEFT OUTER JOIN pais ON vino.ID_pais = pais.ID 
LEFT OUTER JOIN pais_texto ON pais_texto.ID_pais = pais.ID AND pais_texto.ID_idioma = 1 
WHERE activo = 1 
GROUP BY vino.ID 
HAVING nombre LIKE '%blanco%' 
OR do LIKE '%blanco%' 
OR csv_componente_texto LIKE '%blanco%' 
OR anada LIKE '%blanco%' 
OR tamano_texto LIKE '%blanco%' 
ORDER BY tipo.orden_papel, vino.ID_pais, do, precio 
LIMIT 30; 

由其他人提供的答案,没有真正固定的像我自己的答案的问题,所以我就没有标注任何人是正确的,但@ skstar的建议可能有助于进一步提升性能,所以我投了票。谢谢你的帮助。

0

如果WHERE子句中的内部“IN(SELECT)”引起问题的大部分问题,请尝试先选择并保存到临时表中,然后检查临时表...对于这一点,它可能会加快速度这些东西只是作为所有“LIKE”%blanco%“”行的表格,然后你可以通过并加入。我已经看到使用临时表或两个这样的速度极快的东西。

+0

感谢您的回复,RustyH。嵌套的SELECT提供了一个ID列表,然后进入WHERE子句的“vino.ID IN()”部分的括号内。在一个单独的查询生成这些ID不加快速度,因为它仍具有由“vino.ID IN(1,2,3,4等)”,这似乎是非常慢的部分进行过滤。我会尝试第二个建议(将WHERE移动到临时子集表),尽管我不确定这会有多大帮助。 – OMA

0

如何使用JOIN这样的:

LEFT OUTER JOIN (
    SELECT ID_vino 
    FROM vino_componente 
) vc ON vc.ID_vino = vino.ID 

,而不是这样的:

LEFT OUTER JOIN vino_componente ON vino_componente.ID_vino = vino.ID 

让所有的连接只选择特定的领域。但是,我确定问题在于LIKE关键字。

1

查看你的'Explain'结果,有很多'key'列NULL表示索引键在某些表上不可用,尝试在这些表的字段上创建索引,这将加快查询的执行。

请参阅CREATE TABLE语法以添加KEY。或者参见ALTER TABLE语法来添加新的密钥。