Pregunta

La siguiente consulta se cuelga: (aunque las subconsultas realizadas por separado están bien)

No sé cómo hacer que la tabla de explicación se vea bien. Si alguien me dice, lo limpiaré.

select
sum(grades.points)) as p,  
from assignments 
left join grades using (assignmentID) 
where gradeID IN 

(select grades.gradeID 
from assignments 
left join grades using (assignmentID) 
where ... grades.date <= '1255503600' AND grades.date >= '984902400' 
group by     assignmentID order by grades.date DESC);

Creo que el problema está en la tabla de primeros grados ... el tipo ALL con tantas filas parece ser la causa ... Todo está indexado.

Subí la tabla como una imagen. No se pudo obtener el formato correcto: http://imgur.com/AjX34.png

Un comentarista quería la cláusula where completa:

explain extended select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
where gradeID IN 
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC);
¿Fue útil?

Solución

Supongamos que utiliza una base de datos real (es decir, cualquier base de datos excepto MySQL, pero usaré Postgres como ejemplo) para hacer esta consulta:

SELECT * FROM ta WHERE aid IN (SELECT subquery)

una base de datos real vería la subconsulta y estimaría su número de filas:

  • Si el número de filas es pequeño (por ejemplo, menos de unos pocos millones)

Ejecutaría la subconsulta, luego construiría un hash de ID en la memoria, lo que también los hace únicos, que es una característica de IN ().

Luego, si el número de filas extraídas de ta es una pequeña parte de ta, usaría un índice adecuado para tirar de las filas. O, si se selecciona una parte importante de la tabla, simplemente la escaneará por completo y buscará cada ID en el hash, que es muy rápido.

  • Si, sin embargo, el recuento de filas de la subconsulta es bastante grande

La base de datos probablemente la reescribiría como una combinación de combinación, agregando un Sort + Unique a la subconsulta.

Sin embargo, estás usando MySQL. En este caso, no hará nada de esto (volverá a ejecutar la subconsulta para cada fila de su tabla), por lo que tomará 1000 años. Lo siento.

Otros consejos

Ver " La insoportable lentitud de IN " ;: http://www.artfulsoftware.com/infotree/queries.php#568

Súper desordenado, pero: (gracias por la ayuda de todos)

   SELECT * 
   FROM grades
   LEFT JOIN assignments ON grades.assignmentID = assignments.assignmentID
   RIGHT JOIN (

   SELECT g.gradeID
 FROM assignments a
 LEFT JOIN grades g
 USING ( assignmentID ) 
 WHERE a.classID =  '7815'
 AND (
 a.type =30170
 )
 AND g.contactID =7141
  g.points
 REGEXP  '^[-]?[0-9]+[-]?'
 AND g.points !=  '-'
 AND g.points !=  ''
 AND (
 g.pointsposs IS NULL 
 OR g.pointsposs =  ''
 )
 AND g.date <=  '1255503600'
 AND g.date >=  '984902400'
 GROUP BY assignmentID
 ORDER BY g.date DESC
 ) AS t1 ON t1.gradeID = grades.gradeID

Si su subconsulta funciona bien cuando se ejecuta por separado, intente usar UNIR en lugar de IN, como esto:

select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
join
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC) using (gradeID);

Realmente no hay suficiente información para responder a tu pregunta, y has puesto una ... en medio de la cláusula where que es rara. ¿Qué tan grandes son las tablas involucradas y cuáles son los índices?

Dicho esto, si hay demasiados términos en una cláusula in, puede ver un rendimiento gravemente degradado. Reemplace el uso de in con una combinación correcta .

Para empezar, la tabla as_types en la cláusula in no se usa. Unirse a la izquierda no sirve para nada, así que deshazte de él.

Eso deja a la cláusula in teniendo solo la tabla de asignaciones y calificaciones de la consulta externa. Claramente, el lugar donde pertenecen las asignaciones de modificación en la cláusula where para la consulta externa. Debería mover todos los puntos grados = lo que sea a la cláusula on de la combinación izquierda a los grados.

La consulta es un poco difícil de seguir, pero sospecho que la subconsulta no es necesaria en absoluto. Parece que tu consulta es básicamente así:

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE gradeID IN 
(
SELECT grades.gradeID
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE your_conditions = TRUE
);

Pero, no estás haciendo nada realmente sofisticado en la cláusula where de la subconsulta. Sospecho algo mas como

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
GROUP BY groupings
WHERE your_conditions_with_some_tweaks = TRUE;

funcionaría igual de bien.

Si me falta alguna lógica clave aquí, comente de nuevo y editaré / eliminaré esta publicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top