如何优化SQL查询?

时间:2014-08-29 05:12:13

标签: sql sql-server tsql optimization

我有一个SQL查询查询如下,任何人都可以为此建议任何优化;我认为联盟行动的大部分努力都在进行 - 是否还有其他办法可以取得同样的结果? 基本上我想查询UNION的第一部分,如果每条记录没有结果,则需要运行第二部分。请帮忙。  :

SET dateformat dmy; 

WITH incidentcategory 
     AS (
     SELECT 1 ord, i.IncidentId, rl.Description Category FROM incident i
        JOIN  IncidentLikelihood l ON i.IncidentId = l.IncidentId
        JOIN IncidentSeverity s ON i.IncidentId = s.IncidentId
        JOIN LikelihoodSeverity ls ON l.LikelihoodId = ls.LikelihoodId AND s.SeverityId = ls.SeverityId
        JOIN RiskLevel rl ON ls.RiskLevelId = rl.riskLevelId

     UNION 

     SELECT 2 ord, i.incidentid, 
                rl.description Category 
         FROM   incident i 
                JOIN incidentreportlikelihood l 
                  ON i.incidentid = l.incidentid 
                JOIN incidentreportseverity s 
                  ON i.incidentid = s.incidentid 
                JOIN likelihoodseverity ls 
                  ON l.likelihoodid = ls.likelihoodid 
                     AND s.severityid = ls.severityid 
                JOIN risklevel rl 
                  ON ls.risklevelid = rl.risklevelid

                  ) ,
ic AS (
        SELECT ROW_NUMBER() OVER (PARTITION BY i.IncidentId ORDER BY (CASE WHEN incidentTime IS NULL THEN GETDATE() ELSE incidentTime END) DESC,ord ASC) rn,
                        i.incidentid, 
                        dbo.Incidentdescription(i.incidentid, '', 
                        '', 
                        '', '') 
                               IncidentDescription, 
                        dbo.Dateconverttimezonecompanyid(closedtime, 
                        i.companyid) 
                               ClosedTime, 
                        incidenttime, 
                        incidentno, 
                        Isnull(c.category, '') 
                               Category, 
                        opencorrectiveactions, 
                        reportcompleted, 
                        Isnull(classificationcompleted, 0) 
                               ClassificationCompleted, 
                        Cast (( CASE 
                                  WHEN closedtime IS NULL THEN 0 
                                  ELSE 1 
                                END ) AS BIT) 
                               IncidentClosed, 
                        Cast (( CASE 
                                  WHEN investigatorfinishedtime IS NULL THEN 0 
                                  ELSE 1 
                                END ) AS BIT) 
                               InvestigationFinished, 
                        Cast (( CASE 
                                  WHEN investigationcompletetime IS NULL THEN 0 
                                  ELSE 1 
                                END ) AS BIT) 
                               InvestigationComplete, 
                        Cast (( CASE 
                                  WHEN investigatorassignedtime IS NULL THEN 0 
                                  ELSE 1 
                                END ) AS BIT) 
                               InvestigatorAssigned, 
                        Cast (( CASE 
                                  WHEN (SELECT Count(*) 
                                        FROM   incidentinvestigator 
                                        WHERE  incidentid = i.incidentid 
                                               AND personid = 1588 
                                               AND tablename = 'AdminLevels') = 0 
                                THEN 0 
                                  ELSE 1 
                                END ) AS BIT) 
                               IncidentInvestigator, 
                        (SELECT dbo.Strconcat(osname) 
                         FROM   (SELECT TOP 10 osname 
                                 FROM   incidentlocation l 
                                        JOIN organisationstructure o 
                                          ON l.locationid = o.osid 
                                 WHERE  incidentid = i.incidentid 
                                 ORDER  BY l.locorder) loc) 
                               Location, 
                        Isnull((SELECT TOP 1 teamleader 
                                FROM   incidentinvestigator 
                                WHERE  personid = 1588 
                                       AND tablename = 'AdminLevels' 
                                       AND incidentid = i.incidentid), 0) 
                               TeamLeader, 
                        incidentstatus, 
                        incidentstatussearch 
        FROM   incident i 
               LEFT OUTER JOIN incidentcategory c 
                            ON i.incidentid = c.incidentid 
        WHERE  i.isdeleted = 0 
               AND i.companyid = 158 
               AND incidentno <> 0 
               --AND reportcompleted = 1 
               --AND investigatorassignedtime IS NOT NULL 
               --AND investigatorfinishedtime IS NULL 
               --AND closedtime IS NULL
              ),
ic2 AS ( 
SELECT * FROM ic WHERE rn=1
)
SELECT *  FROM ic2

--WHERE rownumber >= 0 
--       AND rownumber < 0 + 10 
--WHERE ic2.incidentid in(53327,53538)
--WHERE ic2.incidentid = 53338

ORDER  BY incidentid DESC 

以下是我得到的执行计划: https://www.dropbox.com/s/50dcpelr1ag4blp/Execution_Plan.sqlplan?dl=0

3 个答案:

答案 0 :(得分:2)

有几个问题:

1)使用UNION ALL而不是UNION ALL来避免额外的操作来聚合数据。

2)尝试将众多函数调用(例如dbo.Incidentdescription())修改为内部表值函数,以便您可以使用CROSS APPLY或OUTER APPLY引用它。特别是,如果那些函数再次引用一个表。

3)再次使用CROSS APPLY或OUTER APPLY将子查询从查询​​的SELECT部分​​移动到FROM部分。

4)完成上述操作后,再次检查执行计划是否有任何缺失的索引。另外,使用STATISTICS TIME,IO on运行查询以验证表的次数  被引用是正确的(有时执行计划会让你走错方向,尤其是涉及函数调用时)......

答案 1 :(得分:0)

由于第一个内部查询生成ord = 1的行,第二个生成ord = 2的行,因此应使用UNION ALL而不是UNION。 UNION将过滤掉相等的行,因为你永远不会获得相等的行,所以使用UNION ALL会更有效。

此外,重写您的查询以不使用WITH构造。我对此有过非常糟糕的经历。只需使用常规派生表。如果查询仍然异常缓慢,请尝试将某些派生表序列化为临时表,然后查询临时表。

答案 2 :(得分:0)

通过删除

尝试替代方法
   (SELECT dbo.Strconcat(osname) 
                         FROM   (SELECT TOP 10 osname 
                                 FROM   incidentlocation l 
                                        JOIN organisationstructure o 
                                          ON l.locationid = o.osid 
                                 WHERE  incidentid = i.incidentid 
                                 ORDER  BY l.locorder) loc) 
                               Location, 
                        Isnull((SELECT TOP 1 teamleader 
                                FROM   incidentinvestigator 
                                WHERE  personid = 1588 
                                       AND tablename = 'AdminLevels' 
                                       AND incidentid = i.incidentid), 0) 
                               TeamLeader
来自SELECT的

。避免在select中使用复杂的函数/子查询。