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相加到最后一行