Sql server CTE查询与类似代码的性能差异
我正在寻求基于标准/最佳实践的查询性能分析。欢迎重新编写或输入代码以优化我的代码 我正在使用一个基于SQL server的基于web的工具来查询我只有执行权限的数据库。没有用于分析查询计划的SSMS环境。我试图找出两组相似代码之间性能差异背后的原因。我已经从Sql server CTE查询与类似代码的性能差异,sql-server,tsql,sql-server-2012,query-performance,Sql Server,Tsql,Sql Server 2012,Query Performance,我正在寻求基于标准/最佳实践的查询性能分析。欢迎重新编写或输入代码以优化我的代码 我正在使用一个基于SQL server的基于web的工具来查询我只有执行权限的数据库。没有用于分析查询计划的SSMS环境。我试图找出两组相似代码之间性能差异背后的原因。我已经从SELECT语句中删除了一些附加字段,这些字段对这两个语句都是通用的,并且会对性能产生同等的影响。此外,由于外部限制,我正在将铸造日期转换回日期时间 案例1:重复且详细的案例陈述和计算。没有额外的CTE,因此少了1个JOIN 案例2:使用附加
SELECT
语句中删除了一些附加字段,这些字段对这两个语句都是通用的,并且会对性能产生同等的影响。此外,由于外部限制,我正在将铸造日期转换回日期时间
案例1:重复且详细的案例
陈述和计算。没有额外的CTE,因此少了1个JOIN
案例2:使用附加的DateCTE
缩短别名,导致额外的连接
目前,案例2的执行时间是案例1的4-5倍
集合1的代码:
WITH CTE AS
(SELECT
C.client_id AS [Client ID]
,CAST(CV.date1 AS DATE) AS SDate
,VT.label AS Service
,MIN(CASE WHEN VT.label='A' THEN CAST(CV.date1 AS DATE) END) OVER (PARTITION BY C.client_id) AS [FirstAssist Date]
,CI.billing_ord AS Ord
FROM C
INNER JOIN CV
ON C.client_id=CV.client_id
LEFT JOIN VT
ON VT.visittype_id=CV.visittype_id
LEFT JOIN CI
ON CI.client_id=C.client_id
)
SELECT DISTINCT
CTE.[Client ID]
,CONVERT(datetime,COALESCE(MIN(CASE WHEN CTE.Service LIKE '%med%' AND CTE.SDate >= CTE.FirstAssistDate THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID])
,CASE WHEN DATEDIFF(day,CTE.FirstAssistDate, MIN(CASE WHEN CTE.Service LIKE '%med%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID])) >=-5
THEN MIN(CASE WHEN CTE.Service LIKE '%med%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) END))
AS [Start Date]
,COALESCE(DATEDIFF(day, CTE.[FirstAssist Date], MIN(CASE WHEN CTE.Service LIKE '%med%eval%' AND CTE.SDate >= CTE.[FirstAssist Date] THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]))
,CASE WHEN DATEDIFF(day, CTE.[FirstAssist Date], MIN(CASE WHEN CTE.Service LIKE '%med%eval%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID])) >= -5
THEN ABS(DATEDIFF(day, CTE.[FirstAssist Date], MIN(CASE WHEN CTE.Service LIKE '%med%eval%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]))) END)
AS [Days to Treat]
FROM CTE
INNER JOIN (SELECT CTE.[Client ID], MIN(CTE.Ord) AS MinOrd FROM CTE GROUP BY CTE.[Client ID]) InsCTE ON CTE.[Client ID]=InsCTE.[Client ID] AND CTE.[Ord]=InsCTE.MinOrd
WHERE 1=1
AND CTE.[Client ID] NOT IN (SELECT [Client ID] FROM CTE WHERE Service LIKE 'B')
AND CTE.SDate BETWEEN '20150701' AND '20170301'
WITH CTE AS
(SELECT
C.client_id AS [Client ID]
,CAST(CV.date1 AS DATE) AS SDate
,VT.label AS Service
,MIN(CASE WHEN VT.label='A' THEN CAST(CV.date1 AS DATE) END) OVER (PARTITION BY C.client_id) AS [FirstAssist Date]
,CI.billing_ord AS Ord
FROM C
INNER JOIN CV
ON C.client_id=CV.client_id
LEFT JOIN VT
ON VT.visittype_id=CV.visittype_id
LEFT JOIN CI
ON CI.client_id=C.client_id
)
,DateCTE AS
(SELECT
[Client ID]
,MIN(CASE WHEN CTE.Service LIKE '%med%eval%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS MedEvalDate
,MIN(CASE WHEN CTE.Service LIKE '%med%eval%' AND CTE.SDate >= CTE.FirstAssistDate THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS FirstMedEvalDate
,MIN(CASE WHEN CTE.Service LIKE '%med%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS MedSvcDate
,MIN(CASE WHEN CTE.Service LIKE '%med%' AND CTE.SDate >= CTE.FirstAssistDate THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS FirstMedSvcDate
FROM CTE
)
SELECT DISTINCT
CTE.[Client ID]
,CONVERT(datetime,COALESCE(DateCTE.FirstMedSvcDate,CASE WHEN DATEDIFF(day,CTE.FirstAssistDate, DateCTE.MedSvcDate) >=-5 THEN DateCTE.MedSvcDate END)) AS [Start Date]
,COALESCE(DATEDIFF(day, CTE.FirstAssistDate, DateCTE.FirstMedEvalDate),CASE WHEN DATEDIFF(day, CTE.FirstAssistDate, DateCTE.MedEvalDate) >= -5
THEN ABS(DATEDIFF(day, CTE.FirstAssistDate, DateCTE.MedEvalDate))END)
AS [Days to Treat]
FROM CTE
INNER JOIN (SELECT CTE.[Client ID], MIN(CTE.Ord) AS MinOrd FROM CTE GROUP BY CTE.[Client ID]) InsCTE ON CTE.[Client ID]=InsCTE.[Client ID] AND CTE.[Ord]=InsCTE.MinOrd
INNER JOIN DateCTE ON CTE.[Client ID]=DateCTE.[Client ID]
WHERE 1=1
AND CTE.[Client ID] NOT IN (SELECT [Client ID] FROM CTE WHERE Service LIKE 'B')
AND CTE.SDate BETWEEN '20150701' AND '20170301'
集合2的代码:
WITH CTE AS
(SELECT
C.client_id AS [Client ID]
,CAST(CV.date1 AS DATE) AS SDate
,VT.label AS Service
,MIN(CASE WHEN VT.label='A' THEN CAST(CV.date1 AS DATE) END) OVER (PARTITION BY C.client_id) AS [FirstAssist Date]
,CI.billing_ord AS Ord
FROM C
INNER JOIN CV
ON C.client_id=CV.client_id
LEFT JOIN VT
ON VT.visittype_id=CV.visittype_id
LEFT JOIN CI
ON CI.client_id=C.client_id
)
SELECT DISTINCT
CTE.[Client ID]
,CONVERT(datetime,COALESCE(MIN(CASE WHEN CTE.Service LIKE '%med%' AND CTE.SDate >= CTE.FirstAssistDate THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID])
,CASE WHEN DATEDIFF(day,CTE.FirstAssistDate, MIN(CASE WHEN CTE.Service LIKE '%med%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID])) >=-5
THEN MIN(CASE WHEN CTE.Service LIKE '%med%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) END))
AS [Start Date]
,COALESCE(DATEDIFF(day, CTE.[FirstAssist Date], MIN(CASE WHEN CTE.Service LIKE '%med%eval%' AND CTE.SDate >= CTE.[FirstAssist Date] THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]))
,CASE WHEN DATEDIFF(day, CTE.[FirstAssist Date], MIN(CASE WHEN CTE.Service LIKE '%med%eval%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID])) >= -5
THEN ABS(DATEDIFF(day, CTE.[FirstAssist Date], MIN(CASE WHEN CTE.Service LIKE '%med%eval%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]))) END)
AS [Days to Treat]
FROM CTE
INNER JOIN (SELECT CTE.[Client ID], MIN(CTE.Ord) AS MinOrd FROM CTE GROUP BY CTE.[Client ID]) InsCTE ON CTE.[Client ID]=InsCTE.[Client ID] AND CTE.[Ord]=InsCTE.MinOrd
WHERE 1=1
AND CTE.[Client ID] NOT IN (SELECT [Client ID] FROM CTE WHERE Service LIKE 'B')
AND CTE.SDate BETWEEN '20150701' AND '20170301'
WITH CTE AS
(SELECT
C.client_id AS [Client ID]
,CAST(CV.date1 AS DATE) AS SDate
,VT.label AS Service
,MIN(CASE WHEN VT.label='A' THEN CAST(CV.date1 AS DATE) END) OVER (PARTITION BY C.client_id) AS [FirstAssist Date]
,CI.billing_ord AS Ord
FROM C
INNER JOIN CV
ON C.client_id=CV.client_id
LEFT JOIN VT
ON VT.visittype_id=CV.visittype_id
LEFT JOIN CI
ON CI.client_id=C.client_id
)
,DateCTE AS
(SELECT
[Client ID]
,MIN(CASE WHEN CTE.Service LIKE '%med%eval%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS MedEvalDate
,MIN(CASE WHEN CTE.Service LIKE '%med%eval%' AND CTE.SDate >= CTE.FirstAssistDate THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS FirstMedEvalDate
,MIN(CASE WHEN CTE.Service LIKE '%med%' THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS MedSvcDate
,MIN(CASE WHEN CTE.Service LIKE '%med%' AND CTE.SDate >= CTE.FirstAssistDate THEN CTE.SDate END) OVER (PARTITION BY CTE.[Client ID]) AS FirstMedSvcDate
FROM CTE
)
SELECT DISTINCT
CTE.[Client ID]
,CONVERT(datetime,COALESCE(DateCTE.FirstMedSvcDate,CASE WHEN DATEDIFF(day,CTE.FirstAssistDate, DateCTE.MedSvcDate) >=-5 THEN DateCTE.MedSvcDate END)) AS [Start Date]
,COALESCE(DATEDIFF(day, CTE.FirstAssistDate, DateCTE.FirstMedEvalDate),CASE WHEN DATEDIFF(day, CTE.FirstAssistDate, DateCTE.MedEvalDate) >= -5
THEN ABS(DATEDIFF(day, CTE.FirstAssistDate, DateCTE.MedEvalDate))END)
AS [Days to Treat]
FROM CTE
INNER JOIN (SELECT CTE.[Client ID], MIN(CTE.Ord) AS MinOrd FROM CTE GROUP BY CTE.[Client ID]) InsCTE ON CTE.[Client ID]=InsCTE.[Client ID] AND CTE.[Ord]=InsCTE.MinOrd
INNER JOIN DateCTE ON CTE.[Client ID]=DateCTE.[Client ID]
WHERE 1=1
AND CTE.[Client ID] NOT IN (SELECT [Client ID] FROM CTE WHERE Service LIKE 'B')
AND CTE.SDate BETWEEN '20150701' AND '20170301'
不幸的是,任何人告诉你的都是猜测,因为没有足够的信息。例如,可能是您的
DateCTE
丢弃了估计的行数(因为当您无法为这类事情编制索引时,SQL如何知道有多少行与通配符匹配?),并且因为SQL选择了一个非常次优的计划(满足您的需要)。但正如前面提到的,任何关于它为什么会发生的说法都只是猜测。最佳做法是查看查询计划,但您不能这样做,所以我不确定有人能帮上什么忙,真的。@ZLK我理解。这就像在没有计划的情况下从大海捞针一样,但如果代码中真的出现了什么东西,那么值得一试。我会试着进一步调查那个日期。如果有一个更好的方式或方法,除了CTE的,通常是不那么密集,我也有兴趣知道。谢谢。当您遇到CTE性能问题时,请丢失CTE并在临时表中填充中间数据。十有八九你的问题消失了。