Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
T-SQL中递归CTE的性能较慢_Sql_Performance_Tsql_Recursion_Common Table Expression - Fatal编程技术网

T-SQL中递归CTE的性能较慢

T-SQL中递归CTE的性能较慢,sql,performance,tsql,recursion,common-table-expression,Sql,Performance,Tsql,Recursion,Common Table Expression,基于社区成员帮助,我有以下代码: use [Credible]; WITH DataSource AS ( SELECT ROW_NUMBER() OVER(ORDER BY epi.[client_id]) AS [row_id] ,epi.[client_id] ,CONVERT(date, epi.[admission_date]) AS [admission_da

基于社区成员帮助,我有以下代码:

      use [Credible];

      WITH DataSource AS
      (
       SELECT
             ROW_NUMBER() OVER(ORDER BY epi.[client_id]) AS [row_id]
            ,epi.[client_id]
            ,CONVERT(date, epi.[admission_date]) AS [admission_date]
            ,CONVERT(date, DATEADD(MONTH, 3, epi.[admission_date])) AS [3Month Date]
            ,CONVERT(date, ISNULL(epi.[discharge_date], GETDATE())) AS [discharge_date]

       FROM 
           [dbo].[ClientEpisode] epi

       WHERE DATEADD(MONTH, 3, [admission_date]) <= ISNULL([discharge_date], GETDATE()) 
  ),
    RecursiveDataSource AS
     (
      SELECT 
            [row_id]
           ,[client_id]
           ,[admission_date]
           ,[3Month Date]
           ,[discharge_date]
           ,0 AS [level]

     FROM 
         DataSource

         UNION ALL

     SELECT 
          ds.[row_id]
         ,ds.[client_id]
         ,ds.[admission_date]
         ,DATEADD(MONTH, 3, rds.[3Month Date])
         ,ds.[discharge_date]
         ,[level] + 1

    FROM 
          RecursiveDataSource rds
          INNER JOIN DataSource ds ON 
          rds.[row_id] = ds.[row_id] AND DATEADD(MONTH, 3, rds.[3Month Date]) < ds.[discharge_date]
    )

     SELECT *

     FROM RecursiveDataSource 

     ORDER BY [row_id]
             ,[level]
     -- OPTION (MAXRECURSION 32767);
如果表中有多达1000条记录,则此代码的工作速度约为30秒

但我的表有14000多条记录,而且还会增加, 代码工作时间为10+++分钟

有没有办法在30秒左右的时间内完成它的表演


感谢您的帮助

因为您在这里寻找性能解决方案,我建议您跳过使用递归CTE,用另一种方法解决这个问题

例如,这方面的一个变体:

DECLARE @DataSource TABLE
(
    [client_id] INT
   ,[adm_date] DATE
   ,[disch_date] DATE
);

INSERT INTO @DataSource ([client_id], [adm_date], [disch_date])
VALUES (1002, '3/11/2005 ', '5/2/2005')
      ,(1002, '8/30/2005 ', '2/16/2007')
      ,(1002, '3/16/2017 ', NULL);

DROP TABLE IF EXISTS #DataSource;
DROP TABLE IF EXISTS #DataNumers;

CREATE TABLE #DataSource
(
    [client_id] INT
   ,[adm_date] DATE
   ,[disch_date] DATE
   ,[diff_in_months] INT
);

CREATE TABLE #DataNumers
(
    [number] INT
);

DECLARE @max_diff_in_months INT;

INSERT INTO #DataSource ([client_id], [adm_date], [disch_date], [diff_in_months])
SELECT [client_id]
      ,[adm_date]
      ,ISNULL([disch_date], GETUTCDATE()) AS [disch_date]
      ,CEILING(DATEDIFF(MONTH, [adm_date], ISNULL([disch_date], GETUTCDATE())) * 1.0 / 3.0) - 1
FROM @DataSource
WHERE DATEADD(MONTH, 3, [adm_date]) <= ISNULL([disch_date], GETUTCDATE());

SELECT @max_diff_in_months = MAX([diff_in_months])
FROM #DataSource;

INSERT INTO #DataNumers ([number])
SELECT TOP (@max_diff_in_months) ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM [master]..[spt_values];

SELECT DS.[client_id]
      ,DS.[adm_date]
      ,DATEADD(MONTH, DN.[number] * 3, [adm_date]) AS [3Month Date]
      ,DS.[disch_date]
FROM #DataSource DS
CROSS APPLY #DataNumers DN
WHERE DS.[diff_in_months] >= DN.[number];
算法如下所示:

只选择我们需要的行 计算每行以月/3为单位的差异 在助手表中生成数字 使用交叉应用生成新行 如果有超过2.5k的数字,可以使用交叉连接,但我在示例中删除了它。此外,我们正在使用[master].[spt_值]生成总周期。但这只是T-SQL中生成数字的一种方法。如果愿意,您可以检查链接并使用其他技术


我们的想法是找出每个[adm_date]和[disch_date]之间的周期,周期是用3个月来度量的,这就是为什么我们使用DATEDIFF和MONTH,然后除以3。我们正在使用以获取上限值。当然您可以生成超出需要的句点,并在最终结果中使用WHERE子句排除句点。

我想我应该首先在DataSource中获取查询并将其拆分为一个临时表,然后尝试针对该临时表运行CTE。我在这里回答了这个问题,但移动了原始问题的答案,因为它实际上是对原始问题的响应e、 例如,以不同的方式进行计算,而不是优化此CTE。我已经把它放进了数据源中,如果你把1,'20010101','20050115'作为一行包含在数据源中,它会跳过最后一行它应该包含的20050101.@seanb在下一行中,CEILINGDATEDIFFMONTH,[adm_date],ISNULL[disch_date],GETDATE*1.0/3.0-1如果你删除-1它可以工作@好了,它工作得很好!关于CEILINGDATEDIFFMONTH、[adm_date]、ISNULL[disch_date]、GETDATE*1.0/3.0的问题您能解释一下吗?和-什么是[主值]…[标普单位值]?我发现了[[master].[dbo]。我的数据库中的spt_值变大了,谢谢你,一如往常!@Hell-1931我在编辑中解释道。现在可以分享性能了吗?@gotqn,它绝对有效-我只需将INSERT INTO值替换为从myDBTable中插入SELECT,并从CEILINGDATEDIFFMONTH中删除-1,[adm_date],ISNULL[disch_date],GETUTCDATE*1.0/3.0-1,因此它将在dich date>3M date之前将3M相加到最后一行