Estoy intentando configurar algunos datos para calcular varias medianas en SQL Server 2008, pero tengo un problema de rendimiento. En este momento, estoy usando este pattern ([otro ejemplo bottom). Sí, no estoy usando un CTE, pero usar uno no solucionará el problema que estoy teniendo de todos modos y el rendimiento es pobre porque las subconsultas row_numeros se ejecutan en serie, no en paralelo.Multiple Row_Number() Llamadas en una única consulta SQL
Aquí hay un ejemplo completo. Debajo del SQL explico más el problema.
-- build the example table
CREATE TABLE #TestMedian (
StateID INT,
TimeDimID INT,
ConstructionStatusID INT,
PopulationSize BIGINT,
SquareMiles BIGINT
);
INSERT INTO #TestMedian (StateID, TimeDimID, ConstructionStatusID, PopulationSize, SquareMiles)
VALUES (1, 1, 1, 100000, 200000);
INSERT INTO #TestMedian (StateID, TimeDimID, ConstructionStatusID, PopulationSize, SquareMiles)
VALUES (1, 1, 1, 200000, 300000);
INSERT INTO #TestMedian (StateID, TimeDimID, ConstructionStatusID, PopulationSize, SquareMiles)
VALUES (1, 1, 1, 300000, 400000);
INSERT INTO #TestMedian (StateID, TimeDimID, ConstructionStatusID, PopulationSize, SquareMiles)
VALUES (1, 1, 1, 100000, 200000);
INSERT INTO #TestMedian (StateID, TimeDimID, ConstructionStatusID, PopulationSize, SquareMiles)
VALUES (1, 1, 1, 250000, 300000);
INSERT INTO #TestMedian (StateID, TimeDimID, ConstructionStatusID, PopulationSize, SquareMiles)
VALUES (1, 1, 1, 350000, 400000);
--TruNCATE TABLE TestMedian
SELECT
StateID
,TimeDimID
,ConstructionStatusID
,NumberOfRows = COUNT(*) OVER (PARTITION BY StateID, TimeDimID, ConstructionStatusID)
,PopulationSizeRowNum = ROW_NUMBER() OVER (PARTITION BY StateID, TimeDimID, ConstructionStatusID ORDER BY PopulationSize)
,SquareMilesRowNum = ROW_NUMBER() OVER (PARTITION BY StateID, TimeDimID, ConstructionStatusID ORDER BY SquareMiles)
,PopulationSize
,SquareMiles
INTO #MedianData
FROM #TestMedian
SELECT MinRowNum = MIN(PopulationSizeRowNum), MaxRowNum = MAX(PopulationSizeRowNum), StateID, TimeDimID, ConstructionStatusID, MedianPopulationSize= AVG(PopulationSize)
FROM #MedianData T
WHERE PopulationSizeRowNum IN((NumberOfRows + 1)/2, (NumberOfRows + 2)/2)
GROUP BY StateID, TimeDimID, ConstructionStatusID
SELECT MinRowNum = MIN(SquareMilesRowNum), MaxRowNum = MAX(SquareMilesRowNum), StateID, TimeDimID, ConstructionStatusID, MedianSquareMiles= AVG(SquareMiles)
FROM #MedianData T
WHERE SquareMilesRowNum IN((NumberOfRows + 1)/2, (NumberOfRows + 2)/2)
GROUP BY StateID, TimeDimID, ConstructionStatusID
DROP TABLE #MedianData
DROP TABLE #TestMedian
El problema con esta consulta es que SQL Server ejecuta tanto de la "ROW__NUMBER() OVER ..." sub-consultas en serie, no en paralelo. Entonces, si tengo 10 de estos cálculos de ROW__NUMBER, los calculará uno después del otro y obtendré un crecimiento lineal, que huele mal. Tengo un sistema de 32 GB de 8 vías Estoy ejecutando esta consulta y me gustaría un poco de paralelismo. Estoy intentando ejecutar este tipo de consulta en una tabla de filas de 5,000,000.
Esto se puede ver mirando el plan de consulta y viendo los Sorts en la misma ruta de ejecución (mostrar el XML del plan de consulta no funcionaría muy bien en SO).
Entonces mi pregunta es esta: ¿Cómo puedo alterar esta consulta para que las consultas ROW_NUMBER se ejecuten en paralelo? ¿Existe una técnica completamente diferente que pueda usar para preparar los datos para cálculos de mediana múltiple?
1, código suficiente para probarlo en mi sistema !! –
+1, porque no sabía que podía usar las cláusulas OVER fuera de las funciones de clasificación, tampoco en SQL 2005. ¡Woot! –
Philip: Para las funciones Aggregate normales, solo la cláusula PARTITION BY, no la parte ORDER BY :-( – RBarryYoung