如何优化使用子查询的查询

时间:2017-11-03 12:06:48

标签: sql sql-server join nested subquery

所以这个SQL查询工作正常,但需要花费太多时间,大约3分钟〜。我想知道是否有可能优化它。并且在JOIN中使用子查询编写了另一个查询,它运行得更快,但它提供了错误的输出。

我们想要达到的目标是为去年每周的每个严重程度获取所有警报和更多过滤警报。这些过滤的警报在“CCALARMS”子查询中描述(或在其他查询中的“SOMETHING”JOIN中)。

也许有些人知道,如何优化第一个查询,或者如何修改第二个查询,以产生正确的输出?使用MSSQL服务器。提前谢谢!

正确查询(需要很长时间):

SELECT 
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) AS YEAR,
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS MONTH,
    rSEV.NAME AS SEVERITY,
    COUNT(rSTA.ALARMIDKEY) AS ALARMS,
    CCALARMS = COUNT(
                 CASE WHEN                     
                    (MAINTMODECRONTAB != 'Y'
                     AND SUPPRESSESCL < 4
                     AND SPMAUTO != 1
                     AND ORIGINALSEVERITY > 0)
                     AND ((AIWAVER = 3 AND EVENTACTOR = 1)
                          OR
                          ((AIWAVER < 3 OR AIWAVER IS NULL)
                           AND ((CONTROLCENTREVIEW = 1
                                 AND ORIGINALSEVERITY = 5)
                                OR (CONTROLCENTREVIEW = 2)
                                OR (ALERTGROUP = 'CHECKLIST')
                               )
                          )
                         )
                THEN rSTA.ALARMIDKEY END)
FROM 
    REPORTER.reporter.REPORTER_STATUS rSTA
INNER JOIN
    REPORTER.reporter.REP_SEVERITY_TYPES rSEV
    ON
    rSTA.ORIGINALSEVERITY = rSEV.SEVERITY
WHERE
    DATEDIFF( wk, rSTA.FIRSTOCCURRENCEDAY, GETDATE()) < 54
    AND
    rSEV.NAME != 'Clear'
GROUP BY
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ),
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
    rSEV.NAME
ORDER BY
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) DESC,
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) DESC

修改后的查询(占用较少,但输出不正确):

SELECT 
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) AS YEAR,
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS MONTH,
    rSEV.NAME AS SEVERITY,
    COUNT(rSTA.ALARMIDKEY) AS ALARMS,
    SOMETHING.ALARMIDKEY_CC_ACTS
FROM 
    REPORTER.reporter.REPORTER_STATUS rSTA
INNER JOIN
    REPORTER.reporter.REP_SEVERITY_TYPES rSEV
    ON
    rSTA.ORIGINALSEVERITY = rSEV.SEVERITY
JOIN
( 
            SELECT ALARMIDKEY, COUNT(ALARMIDKEY) AS ALARMIDKEY_CC_ACTS FROM REPORTER.reporter.REPORTER_STATUS WHERE
                    (MAINTMODECRONTAB != 'Y'
                     AND SUPPRESSESCL < 4
                     AND SPMAUTO != 1
                     AND ORIGINALSEVERITY > 0)
                     AND ((AIWAVER = 3 AND EVENTACTOR = 1)
                          OR
                          ((AIWAVER < 3 OR AIWAVER IS NULL)
                           AND ((CONTROLCENTREVIEW = 1
                                 AND ORIGINALSEVERITY = 5)
                                OR (CONTROLCENTREVIEW = 2)
                                OR (ALERTGROUP = 'CHECKLIST')
                               )
                          )
                         )
    GROUP BY ALARMIDKEY ) AS SOMETHING
ON SOMETHING.ALARMIDKEY = rSTA.ALARMIDKEY
WHERE
      DATEDIFF( wk, rSTA.FIRSTOCCURRENCEDAY, GETDATE()) < 54
      AND
      rSEV.NAME != 'Clear'
GROUP BY
      DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ),
      DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
      rSEV.NAME,
      SOMETHING.ALARMIDKEY_CC_ACTS
ORDER BY
      DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) DESC,
      DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) DESC

还附上输出应该是的图片:

首先查询(ok):
OKQUERY

第二次查询(输出错误):
BADQUERY

1 个答案:

答案 0 :(得分:0)

一个问题是非可搜索的WHERE子句表达式,它可以有效地阻止FIRSTOCCURRENCEDAY上的索引(假设存在一个索引):

WHERE
    DATEDIFF( wk, rSTA.FIRSTOCCURRENCEDAY, GETDATE()) < 54
    AND
    rSEV.NAME != 'Clear'

尝试重构,使该函数不直接应用于列:

WHERE
    rSTA.FIRSTOCCURRENCEDAY < DATEADD(week, -54, GETDATE())
    AND
    rSEV.NAME != 'Clear'

如果仍有问题,请在问题中添加CREATE TABLE DDL(包括约束和索引),并将实际执行计划上传到https://www.brentozar.com/pastetheplan/