简体   繁体   中英

How to optimize a query which is using subquery

So there's this SQL query which works fine, but takes too much time, around 3 minutes~. I wonder would it be possible to optimize it. And there's another query written with a subquery in a JOIN, which works faster, but it provides wrong output.

What we want to achieve is to get all alarms and more filtered alarms for every severity of every week of last year passed. Those filtered alarms are described in "CCALARMS" subquery (or in "SOMETHING" JOIN in other query ).

Maybe some of you know, how to optimize the first query, or how to modify second query, to produce correct output? Using MSSQL server. Thanks in advance!

Correct Query (takes long time):

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

Modified query (takes less, but output is not correct):

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

Also attaching pictures of what the output should be:

First query (ok):
OKQUERY

Second query (bad output):
热门查询

One issue is the non-sargable WHERE clause expression that prevents an index on FIRSTOCCURRENCEDAY efficiently (assuming one exists):

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

Try refactoring such that the function is not applied to the column directly:

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

If you still have problems, add CREATE TABLE DDL to your question (including constraints and indexes) and upload your actual execution plans to https://www.brentozar.com/pastetheplan/ .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM