Вопрос

This SQL query is taking a whooping 230.63 seconds (almost 4 minutes!).

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;

This is the 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

If I remove the nested "IN (SELECT)" from the WHERE clause, it gets down to a more reasonable 8 seconds, which is still pretty slow, but not so ridiculously slow.

So why is this working so slowly and how can I improve this to get better speed?

Это было полезно?

Решение 4

Well, I've finally found myself a way to speed things up using a combination of GROUP_CONCAT, GROUP BY and HAVING to replace the nested SELECT which was being executed thousands of times (once per record).

Now the query is still not speedy (it takes a good 10 seconds to run), but it's not so incredibly slow (before, it took almost 4 minutes), so it's still a pretty BIG improvement!

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;

From the answers provided by other people, none really fixed the problem like my own answer, so I won't mark any of them as correct, though @skstar's suggestion might be helpful to further enhance performance, so I've voted it up. Thanks for your help.

Другие советы

See your 'Explain' result, there are many 'key' columns NULL means Index keys not available on some tables, try create index on the fields on those tables, it will speed up the query execution.

See CREATE TABLE syntax to Add KEY. Or see ALTER TABLE syntax to add new Key.

if the inner "IN (SELECT)" from the WHERE clause, is causing ht bulk of your problems try doing that select first and saving to a temp table then check the temp table... for that matter it might speed things up to make just a table of all the "LIKE "%blanco%"" rows that then you can go through and join with. I have seen using a temp table or two drastically speed things like this up.

How about using JOIN like this:

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

instead of this:

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

So that all JOINs only selects the specific fields. But, I am sure that the problem is the LIKE keywords.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top