Sql server CTE查询与类似代码的性能差异

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:使用附加

我正在寻求基于标准/最佳实践的查询性能分析。欢迎重新编写或输入代码以优化我的代码

我正在使用一个基于SQL server的基于web的工具来查询我只有执行权限的数据库。没有用于分析查询计划的SSMS环境。我试图找出两组相似代码之间性能差异背后的原因。我已经从
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并在临时表中填充中间数据。十有八九你的问题消失了。