【发布时间】:2023-03-06 19:31:02
【问题描述】:
我正在尝试设置一些数据来计算 SQL Server 2008 中的多个中位数,但我遇到了性能问题。现在,我正在使用这个pattern([另一个例子bottom)。是的,我没有使用 CTE,但是使用 CTE 并不能解决我遇到的问题,而且性能很差,因为 row_number 子查询是串行运行的,而不是并行运行的。
这是一个完整的例子。在 SQL 下我更详细地解释了这个问题。
-- 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
此查询的问题在于 SQL Server 以串行方式而不是并行方式执行两个“ROW__NUMBER() OVER...”子查询。所以如果我有 10 个这样的 ROW__NUMBER 计算,它会一个接一个地计算它们,我得到线性增长,这很糟糕。我有一个运行此查询的 8 路 32GB 系统,我希望有一些并行性。我正在尝试在 5,000,000 行表上运行此类查询。
我可以通过查看查询计划并查看同一执行路径中的排序来告诉它这样做(在 SO 上显示查询计划的 XML 并不能很好地工作)。
所以我的问题是:如何更改此查询以便 ROW_NUMBER 查询并行执行?有没有一种完全不同的技术可以用来为多个中值计算准备数据?
【问题讨论】:
-
+1,足够的代码可以在我的系统上试用!!
-
+1,因为我不知道您可以在排名函数之外使用 OVER 子句——在 SQL 2005 中也是如此。哇!
-
Philip:对于普通的聚合函数,只有 PARTITION BY 子句,而不是 ORDER BY 部分 :-(
-
@RBarry:无论输入的顺序如何,AVG、SUM、COUNT、MAX、MIN 等都应该给出相同的结果。
-
Remus:ORDER BY 部分意味着顺序聚合。换句话说,SUM(..) OVER(ORDER BY id) 将产生运行总计(根据 SQL 标准)。不幸的是,SQL Server 没有实现它。
标签: sql sql-server tsql