2011-08-15 7 views
7

Tengo una consulta SQL particular que parece sufrir un misterioso problema de rendimiento. Ésta es la consulta:Necesito mejorar el rendimiento de SQL Query usando funciones de agregado

SELECT COUNT(LengthOfTime) AS TotalTime, 
     SUM(LengthOfTime) AS TotalLength, 
     SUM(LengthOfTime)/COUNT(LengthOfTime) AS AverageTime, 
     SUM(Pops)/COUNT(LengthOfTime) AS AveragePop 
    FROM ((SELECT * 
      FROM (SELECT *, ID & YearRec AS ID2 
        FROM MyFirstTable 
       UNION ALL 
       SELECT *, ID & YearRec AS ID2 
        FROM Table2011) AS TEMP 
      WHERE STARTTIME >= '8/1/2011 00:00:00' 
      AND StartTime <= '8/5/2011 23:59:59') AS TEMP2 
    JOIN AppleTable ON TEMP2.Reason = AppleTable.Skills) 
    JOIN PeopleTable ON TEMP2.Operator = PeopleTable.Operators 
WHERE AppleTable.[ON] = 1 
    AND PeopleTable.[ON] = 1 
    AND Rec_Type = 'SECRET AGENT' 

El problema aquí es que esta consulta se ejecuta muy rápidamente (0:00 a 0:02) cuando se ejecuta por un lapso de 5 días, pero muy lentamente (01:20-01:45) para un lapso de 6 días.

hay aproximadamente 105.000 registros por día en las Tablas (MyFirstTable y Table2011).

Mi pregunta: ¿Hay un límite superior para el número de filas que puede pasar una función agregada antes de ver un problema de rendimiento grave en SQL Server? (Actualmente se utiliza 2008 R2)

+0

son sus estadísticas actualizadas, ¿ha reconstruido índices recientemente? –

+0

Parece que se está desbordando de una operación en memoria a una que requiere disco. No estoy familiarizado con los detalles de ajuste de MySQL, pero si hay un parámetro de asignación de memoria para el espacio de trabajo temporal, puede intentar aumentar eso. –

+1

@Jim: no es mySQL ... –

Respuesta

4

No, no hay un límite superior predefinido para las funciones agregadas.

La asimetría en el rendimiento es probable afectada por uno o varios de los siguientes:

  • Antiguo y/o estructura del índice inadecuada
  • ejecución caché del plan
  • Los datos en caché
  • tamaño de los datos
  • no estar uniforme (los primeros cinco días son 10 filas mientras que el sexto es 100 filas B)

Puede ejecutar la consulta en SSMS y ver el plan de ejecución real. Esto le indicará los lugares donde el costo de ejecutar la consulta es el más alto y eso lo ayudará a determinar el mejor curso de acción.

Editar basado en los comentarios:

Si no hay un índice en Table2011 que contiene [STARTTIME], a continuación, crear una. Si hay un índice, pero está siendo ignorado, entonces debes averiguar por qué. Si está fragmentado, la reconstrucción del índice definitivamente ayudará. Aquí es cómo reconstruir

ALTER INDEX [YourIndexName] ON [dbo].[Table2011] REBUILD WITH (STATISTICS_NORECOMPUTE = ON);

Alternativamente, usted puede hacer esto en SSMS - busque el índice específico en el navegador de objetos, haga clic y reconstruir.

+0

Miré el plan de ejecución real. El 97% del costo proviene del "Escaneo de tabla" en la Tabla2011. Esto es después de predicar el StartTime antes de la UNIÓN – dan042988

+0

@ dan042988 respuesta actualizada –

+0

Gracias por apuntarme en la dirección correcta. Terminé usando el plan de ejecución real para crear un nuevo índice 'USO [NombreBaseDatos] GO CREATE NONCLUSTERED ÍNDICE [QueryIndex1] ON [dbo]. [Table2011] ([Rec_Type], [Hora de inicio]) INCLUYEN ([ Operador], [LengthOfTime], [Pop], [Reason]) GO' – dan042988

9

Respuesta corta: No, no hay un número mágico de registros que causarán que MSSQL comience a funcionar mal.

Ahora, es posible consultas no escala bien y, como consecuencia, cuanto mayor sea el conjunto de datos del [exponencialmente] peor se lleva a cabo.

Un gran problema que vas a tener es que estás predicando el StartTime después de las declaraciones UNIONED. En su lugar, intente predicar eso en sus dos selecciones antes de la UNIÓN. Eso debería marcar una gran diferencia, especialmente si indexas ambas tablas en StartTime (generando índice busca en esas tablas).

SELECT * FROM (
SELECT *, ID & YearRec AS ID2 FROM MyFirstTable 
    WHERE STARTTIME >= '8/1/2011 00:00:00' 
    AND STARTTIME <= '8/5/2011 23:59:59' 
UNION ALL SELECT *, ID & YearRec AS ID2 
FROM Table2011 
    WHERE STARTTIME >= '8/1/2011 00:00:00' 
    AND STARTTIME <= '8/5/2011 23:59:59' 
) AS TEMP 

Es posible que también pueda realizar una refacturación adicional de su código.

+0

+1 - muy buen punto acerca de la ubicación del 'WHERE'. –

+0

Daré +1 para detectar la ubicación de 'UNION'. Si se puede mover más lejos (tener las 2 tablas unidas por separado a las demás y agrupadas y luego usar los agregados), puede aumentar aún más el rendimiento. Puede que ni siquiera necesite UNION al final, solo usando 'countFromSubquery1 + countFromSubquery2 AS TotalTime', etc. –

+0

Lo sentimos, pero el optimizador de consultas debe manejar esto, y el plan de consulta debe mostrar si esta condición se aplica dentro de las sub partes fuera del Unión. Debería hacer ZERO diferencia en el rendimiento. – TomTom

Cuestiones relacionadas