递归cte工作很慢

时间:2015-04-17 08:52:58

标签: performance sql-server-2008 common-table-expression

我想基于某些列对行进行分组,即如果连续行的这些列中的数据相同,则为它们分配相同的组号,如果更改了它,则分配新的行。这变得很复杂,因为列中的相同数据可能稍后出现在其他一些行中,因此它们必须被赋予另一个组号,因为它们不在具有前一组的连续行中。 为此目的,我使用了 cte ,它也提供了正确的输出,但速度太慢,超过75k +行的迭代大约需要15分钟。我使用的代码是:

WITH 
cte  AS (SELECT ROW_NUMBER () OVER (ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd) AS RowNumber, 
           Opnamenummer, Patient_ID, AfdelingsCode, Opnamedatum, Opnamedatumtijd, Ontslagdatum, Ontslagdatumtijd, IsSpoedopname, OpnameType, IsNuOpgenomen, SpecialismeCode, Specialismen
      FROM t_opnames)

SELECT * INTO #ttt FROM cte;

WITH cte2 AS (SELECT TOP 1 RowNumber, 
                 1 AS GroupNumber, 
                 Opnamenummer, Patient_ID, AfdelingsCode, Opnamedatum, Opnamedatumtijd, Ontslagdatum, Ontslagdatumtijd, IsSpoedopname, OpnameType, IsNuOpgenomen, SpecialismeCode, Specialismen
      FROM #ttt
      ORDER BY RowNumber
    UNION ALL
    SELECT c1.RowNumber, 
           CASE
               WHEN c2.Afdelingscode <> c1.Afdelingscode
                 OR c2.Patient_ID <> c1.Patient_ID
                 OR c2.Opnametype <> c1.Opnametype 
            THEN c2.GroupNumber + 1
               ELSE c2.GroupNumber
           END AS GroupNumber, 
           c1.Opnamenummer,c1.Patient_ID,c1.AfdelingsCode,c1.Opnamedatum,c1.Opnamedatumtijd,c1.Ontslagdatum,c1.Ontslagdatumtijd,c1.IsSpoedopname,c1.OpnameType,c1.IsNuOpgenomen, SpecialismeCode, Specialismen
   FROM cte2 c2
    JOIN #ttt c1 ON c1.RowNumber = c2.RowNumber + 1
   ) 

SELECT *
  FROM cte2
  OPTION (MAXRECURSION 0) ;

 DROP TABLE #ttt

我尝试通过将cte的输出放在临时表中来提高性能。这增加了性能,但仍然太慢了。那么,如何将此代码的性能提高到在75k +记录下运行10秒以内?取消查询前的输出为:Screenshot。从图像中可以看出,RowNumber 3,5和6中的Afdelingscode,Patient_ID和Opnametype列中的数据相同,但由于行的并发性,它们具有不同的GroupNumber。

1 个答案:

答案 0 :(得分:1)

没有数据它不是那么容易测试但我会首先尝试不使用临时表,只是从开始到结束使用两个cte,即;

;WITH 
cte  AS (...),
cte2 AS (...) 
select * from cte2 
OPTION (MAXRECURSION 0);

不知道索引等...例如,你在第一个cte中做了很多订购。是否支持索引(或一个多列索引)?

如果没有数据,我可以选择使用它,但是看看这个:

CASE
  WHEN    c2.Afdelingscode <> c1.Afdelingscode
       OR c2.Patient_ID <> c1.Patient_ID
       OR c2.Opnametype <> c1.Opnametype 
          THEN c2.GroupNumber + 1
  ELSE c2.GroupNumber

我会尝试查看row_number中的partition by语句

所以试着运行:

WITH 
cte  AS (
    SELECT ROW_NUMBER () OVER (PARTITION BY Afdelingscode , Patient_ID  ,Opnametype  ORDER BY Patient_ID, Opnamenummer, SPECIALISMEN, Opnametype, OntslagDatumTijd ) AS RowNumber, 
           Opnamenummer, Patient_ID, AfdelingsCode, Opnamedatum, Opnamedatumtijd, Ontslagdatum, Ontslagdatumtijd, IsSpoedopname, OpnameType, IsNuOpgenomen
      FROM t_opnames)