首页 文章

除非使用临时表,否则查询执行效果不佳

提问于
浏览
1

以下查询大约需要1分钟才能运行,并具有以下IO统计信息:

SELECT T.RGN, T.CD, T.FUND_CD, T.TRDT, SUM(T2.UNITS) AS TotalUnits
FROM dbo.TRANS AS T
JOIN dbo.TRANS AS T2 ON T2.RGN=T.RGN AND T2.CD=T.CD AND T2.FUND_CD=T.FUND_CD AND T2.TRDT<=T.TRDT
JOIN TASK_REQUESTS AS T3 ON T3.CD=T.CD AND T3.RGN=T.RGN AND T3.TASK = 'UPDATE_MEM_BAL'
GROUP BY T.RGN, T.CD, T.FUND_CD, T.TRDT

(4447行受影响)表'交易' . 扫描计数5977,逻辑读取7527408,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.表'TASK_REQUESTS' . 扫描计数1,逻辑读取11,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0 .

SQL Server执行时间:CPU时间= 58157毫秒,已用时间= 61437毫秒 .

如果我改为引入临时表,则查询会快速返回并执行较少的逻辑读取:

CREATE TABLE #MyTable(RGN VARCHAR(20) NOT NULL, CD VARCHAR(20) NOT NULL, PRIMARY KEY([RGN],[CD]));
INSERT INTO #MyTable(RGN, CD) SELECT RGN, CD FROM TASK_REQUESTS WHERE TASK='UPDATE_MEM_BAL';

SELECT T.RGN, T.CD, T.FUND_CD, T.TRDT, SUM(T2.UNITS) AS TotalUnits
FROM dbo.TRANS AS T
JOIN dbo.TRANS AS T2 ON T2.RGN=T.RGN AND T2.CD=T.CD AND T2.FUND_CD=T.FUND_CD AND T2.TRDT<=T.TRDT
JOIN #MyTable AS T3 ON T3.CD=T.CD AND T3.RGN=T.RGN
GROUP BY T.RGN, T.CD, T.FUND_CD, T.TRDT

(4447行受影响)表'工作台' . 扫描计数5974,逻辑读取382339,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0.表'TRANSACTIONS' . 扫描计数4,逻辑读取4547,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0.表'#MyTable ____________________________________________________________________________________________________________ 000000000013' . 扫描计数1,逻辑读取2,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0 .

SQL Server执行时间:CPU时间= 1420毫秒,已用时间= 1515毫秒 .

对我来说有趣的是,TASK_REQUEST表是一个小表(目前是3行),统计数据是最新的 . 知道为什么会出现这样不同的执行计划和执行时间吗?理想情况下如何改变事物,以便我不需要使用临时表来获得不错的性能?

执行计划中唯一真正的区别是临时表版本引入了索引假脱机(eager spool)操作 .

3 回答

  • 1

    你正在为每一行进行字符串比较 . 临时表版本丢弃该比较 . 字符串比较不是特别快,并且我将首先看作是额外计算成本的来源 .

  • 0

    这只是好奇心,我没有特别的理由相信它会更快但你尝试过:

    SELECT T.RGN, T.CD, T.FUND_CD, T.TRDT, SUM(T2.UNITS) AS TotalUnits 
    FROM dbo.TRANS AS T 
    JOIN dbo.TRANS AS T2 ON T2.RGN=T.RGN AND T2.CD=T.CD AND T2.FUND_CD=T.FUND_CD AND T2.TRDT<=T.TRDT 
    JOIN TASK_REQUESTS AS T3 ON T3.CD=T.CD AND T3.RGN=T.RGN     
    WHERE T3.TASK = 'UPDATE_MEM_BAL' 
    GROUP BY T.RGN, T.CD, T.FUND_CD, T.TRDT
    
  • 0
    ;WITH MyTable AS
    ( 
        SELECT RGN, CD FROM TASK_REQUESTS WHERE TASK = 'UPDATE_MEM_BAL'
    )
    SELECT t.RGN, t.CD, t.FUND_CD, t.TRDT, SUM(t2.UNITS) [TotalUnits]
    FROM dbo.TRANS t
    JOIN dbo.TRANS t2 ON (t2.RGN = t.RGN 
                      AND t2.CD = t.CD 
                      AND t2.FUND_CD = t.FUND_CD 
                      AND t2.TRDT <= t.TRDT)
    JOIN MyTable t3 ON (t3.CD = t.CD AND t3.RGN = t.RGN)
    GROUP BY t.RGN, t.CD, t.FUND_CD, t.TRDT
    

相关问题