Ich versuche, einige Daten zu berechnen, mehrere Mediane in SQL Server 2008 zu berechnen, aber ich habe ein Leistungsproblem. Im Moment verwende ich diese pattern ([ein anderes Beispiel bottom). Ja, ich verwende kein CTE, aber die Verwendung von einem wird das Problem, das ich sowieso habe, nicht beheben, und die Leistung ist schlecht, weil die row_number-Teilabfragen seriell und nicht parallel ablaufen.Mehrere Row_Number() Aufrufe in einer einzelnen SQL-Abfrage
Hier ist ein vollständiges Beispiel. Unter dem SQL erkläre ich das Problem mehr.
-- 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
Das Problem bei dieser Abfrage ist, dass SQL Server sowohl des ausführt "ROW__NUMBER() OVER ..." Unterabfragen in seriell, nicht parallel. Wenn ich also 10 dieser ROW__NUMBER-Berechnungen habe, berechnet sie sie nacheinander und ich bekomme lineares Wachstum, was stinkt. Ich habe ein 8-Wege-32GB-System, auf dem ich diese Abfrage ausführe, und ich würde etwas Parallelität lieben. Ich versuche, diese Art von Abfrage auf einer 5.000.000 Row-Tabelle auszuführen.
Ich kann es tun, indem ich auf den Abfrageplan schaue und die Sortierungen im selben Ausführungspfad sehe (die Anzeige des XML des Abfrageplans würde auf SO nicht wirklich gut funktionieren).
Meine Frage ist also: Wie kann ich diese Abfrage so ändern, dass die ROW_NUMBER-Abfragen parallel ausgeführt werden? Gibt es eine völlig andere Technik, die ich verwenden kann, um die Daten für mehrere Median-Berechnungen vorzubereiten?
+1, genug, um Code auf meinem System, um zu versuchen !! –
+1, weil ich nicht wusste, dass Sie OVER-Klauseln außerhalb von Ranking-Funktionen verwenden könnten - auch in SQL 2005 nicht weniger. Woot! –
Philip: Für die normalen Aggregatfunktionen sollte nur die PARTITION BY-Klausel, nicht jedoch der ORDER BY-Teil :-( – RBarryYoung