SQLSERVER处理CPU密集逻辑效率低
时间:2010-12-29 来源:qiang5714
今天改一处效率问题,对一个临时表进行分段累加计算,累加方式为累积(Cumulative Aggregations),大约9万条记录的表,时间超过三分钟。
执行环境:
SQL SERVER 2005 ENTERPRISE EDITION
8 CPU CORES
16G MAXSERVERMEMORY
累加算法如下:
BEGIN TRAN
UPDATE #JCCMX SET
[JC] = (SELECT SUM(MT_0.ZC) AS MT_0_ZC_SUM FROM #JCCMX AS MT_0 WHERE (MT_0.CLID = #JCCMX.CLID) AND (MT_0.ID <= #JCCMX.ID))
ROLLBACK
执行计划可以想象,内连接驱动假脱机(Inner Join Drived Eager Spool)。其中假脱机运算符占据了多数的CPU时间。
一开始打算使用开窗聚合函数(Window Aggregations),查资料发现SQL SERVER 2005只为聚合函数实现了带Partion语句的开窗,不支持Order语句,即:
SELECT SUM(ZC) OVER (PARTITION BY CLID)
不支持:
SELECT SUM(ZC) OVER (PARTITION BY CLID ORDER BY ID)
无奈放弃。
使用游标算法,时间稍好,90s,但是也难接受。
BEGIN TRAN
CREATE INDEX IDX ON #JCCMX(ID, CLID) INCLUDE(JC, ZC)
DECLARE @ID INT
DECLARE @OID INT
DECLARE @NID INT
DECLARE @RN INT
DECLARE @ZC FLOAT
DECLARE @SUM FLOAT
DECLARE CUR CURSOR FOR SELECT CLID, ZC, ID FROM #JCCMX
OPEN CUR
FETCH NEXT FROM CUR INTO @NID, @ZC, @ID
WHILE @@FETCH_STATUS = 0
BEGIN
IF @OID = @NID
SET @SUM = @SUM + @ZC
ELSE
SET @SUM = @ZC
UPDATE #JCCMX
SET JC = @SUM
WHERE ID = @ID;
SET @OID = @NID
FETCH NEXT FROM CUR INTO @NID, @ZC, @ID
END
CLOSE CUR
DEALLOCATE CUR
ROLLBACK
于是放弃对SQL SERVER的幻想,将上述游标代码使用DELPHI实现,使用AppServer计算JC列。
开发机(Core 2/2G),9万条记录,1s以内计算完毕。