由于嵌套的SELECT,SQL查询速度极慢。我怎样才能提高速度?

时间:2014-04-15 02:26:04

标签: php mysql sql performance nested

这个SQL查询需要230.63秒(差不多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 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

如果我删除嵌套" IN(SELECT)"从WHERE子句开始,它会下降到更合理的8秒,这仍然很慢,但不是那么可笑。但

那么为什么这种工作如此缓慢?如何才能提高速度以获得更好的速度呢?

4 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

如果来自WHERE子句的内部“IN(SELECT)”导致你的大部分问题尝试首先选择并保存到临时表然后检查临时表...对于这个问题它可能加速事情最多只能制作一个包含所有“LIKE”%blanco%“”行的表,然后你可以通过这些行来加入。我已经看到使用一个或两个临时表来快速加速这样的事情。

答案 2 :(得分: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

这样所有JOIN只选择特定字段。但是,我确信问题是LIKE关键字。

答案 3 :(得分: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的建议可能有助于进一步提升绩效所以我已经投票了。谢谢你的帮助。