2010-08-05 6 views
12

ACTUALIZAR:Esta consulta SELECT tarda 180 segundos en terminar

Solo por mencionarlo en un lugar más visible. Cuando cambié IN por =, el tiempo de ejecución de la consulta pasó de 180 a 0.00008 segundos. Ridícula diferencia de velocidad.


¡Esta consulta de SQL tarda 180 segundos en finalizar! ¿Cómo es eso posible? ¿Hay alguna manera de optimizarlo para ser más rápido?

SELECT IdLawVersionValidFrom 
FROM question_law_version 
WHERE IdQuestionLawVersion IN 
    (
    SELECT MAX(IdQuestionLawVersion) 
    FROM question_law_version 
    WHERE IdQuestionLaw IN 
    (
    SELECT MIN(IdQuestionLaw) 
    FROM question_law 
    WHERE IdQuestion=236 AND IdQuestionLaw>63 
    ) 
) 

Hay solo 5000 filas en cada tabla, por lo que no debería ser tan lenta.

+5

Cualquier diferencia si cambia el '' IN' a = '? –

+7

Esos nombres de columnas dañan mi cerebro. ¿Puedes explicar qué se supone que debe hacer la consulta? – RedFilter

+0

@Martin Smith sería sorprendente (y educativo para mí) si hace alguna diferencia. –

Respuesta

16

Cualquier diferencia si cambia el IN a =?

Si alguien quiere investigar más sobre esto, acabo de hacer una prueba y me pareció muy fácil de reproducir.

Crear tabla

CREATE TABLE `filler` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) 

Crear Procedimiento

CREATE PROCEDURE `prc_filler`(cnt INT) 
BEGIN 
     DECLARE _cnt INT; 
     SET _cnt = 1; 
     WHILE _cnt <= cnt DO 
       INSERT 
       INTO filler 
       SELECT _cnt; 
       SET _cnt = _cnt + 1; 
     END WHILE; 
END 

Populate Tabla

call prc_filler(5000) 

Consulta 1

SELECT id 
FROM filler 
WHERE id = (SELECT MAX(id) FROM filler WHERE id = 
(SELECT MIN(id) 
    FROM filler 
    WHERE id between 2000 and 3000 
    ) 
) 

Equals Explain Output http://img689.imageshack.us/img689/5592/equals.png

Consulta 2 (mismo problema)

SELECT id 
FROM filler 
WHERE id in (SELECT MAX(id) FROM filler WHERE id in 
(SELECT MIN(id) 
    FROM filler 
    WHERE id between 2000 and 3000 
    ) 
) 

In Explain Output http://img291.imageshack.us/img291/8129/52037513.png

+0

Me gustaría que algunos expertos de MySQL comenten sobre la diferencia en el rendimiento. Claramente, las subconsultas van a devolver 1 fila solamente, de modo que el operador correcto es igual, pero ¿por qué el uso de IN haría una diferencia de rendimiento tan grande cuando solo se verifica si el valor se encuentra en un conjunto de resultados de 1 fila? – wadesworld

+3

@Wade - La respuesta de Mark aquí tiene eso cubierto. Creo que http://stackoverflow.com/questions/3417074/why-would-an-in-condition-be-slower-than-in-sql/3417190#3417190 –

12

Here is a good explanation why = is better than IN

MySQL tiene problemas con las consultas internas - no está bien utilizando índices (en su caso).

  1. asegurarse de que tiene índices en todos los campos de la unión/en/etc fin
  2. obtener los valores máximo y mínimo de una consulta (uso procedimiento almacenado para toda esta cosa si desea omitir las múltiples peticiones de arriba o simplemente no hacer una petición con varias consultas

de todos modos:.

SELECT 
     IdLawVersionValidFrom 
FROM 
     question_law_version 
    JOIN 
     question_law 
     ON 
     question_law_version.IdQuestionLaw = question_law.IdQuestionLaw 
WHERE 
     question_law.IdQuestion=236 
    AND 
     question_law.IdQuestionLaw>63 

ORDER BY 
     IdQuestionLawVersion DESC, 
     question_law.IdQuestionLaw ASC 
LIMIT 1 
+0

+1 Quise mencionar índices, pero ... de alguna manera ... no :) – Unreason

+0

En realidad, el comentario de Martin Smith es la respuesta correcta. –

+0

@Richard Knop - ¿Mi consulta funcionó para usted o no? –

4

Usted puede utilizar EXPLAIN para averiguar cómo es posible que una consulta para ejecutar tan lento.

A MySQL no le gustan las subselecciones anidadas, por lo que probablemente lo que sucede es que va y ordena en el disco para obtener el mínimo y el máximo y no reutiliza los resultados.

Reescribir como uniones probablemente lo ayude.

Si sólo en busca de una rápida prueba de errores: (! Publicar mi comentario como una respuesta ya que aparentemente hizo hacer una diferencia)

SET @temp1 =  
    (
    SELECT MIN(IdQuestionLaw) 
    FROM question_law 
    WHERE IdQuestion = 236 AND IdQuestionLaw > 63 
) 

SET @temp2 = 
    (
    SELECT MAX(IdQuestionLawVersion) 
    FROM question_law_version 
    WHERE IdQuestionLaw = @temp1 
) 

SELECT IdLawVersionValidFrom 
FROM question_law_version 
WHERE IdQuestionLawVersion = @temp2 
+0

En realidad, el comentario de Martin Smith es la respuesta correcta. –

+0

Totalmente de acuerdo y le dio +1 a eso. Observe su uso de 'EXPLAIN' :) – Unreason

Cuestiones relacionadas