我有一个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
答案 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中使用复杂的函数/子查询。