SSMS中的CTE与温度表

时间:2019-07-03 15:05:59

标签: stored-procedures ssms common-table-expression temp-tables

我正在努力优化具有3个内部联接和5个左联接的查询。我面临着一个古老的问题,即使用多个CTE或多个临时表来最大程度地减少将结果返回到我的应用所需的时间。 我已经在Stack和其他地方查看了许多答案,但是我对所要处理的问题并没有提出足够接近的问题。  这是一些伪代码,可以从一开始就显示我正在使用的东西:

@partnerships =
    EXTRACT name string,
            createdon DateTime?,
            address1_stateorprovince string
    FROM "/Data/Partnerships"
    USING Extractors.Text(skipFirstNRows : 1, silent : true, quoting : false, delimiter : '\u0001');

@partnerships =
    SELECT name,
           (DateTime)createdon,
           ((DateTime)createdon).Date AS createdonDate,    // Just the date portion for the JOIN later on
           address1_stateorprovince
    FROM partnerships
    WHERE createdon IS NOT NULL;    // I have assumed this filter is necessary given your nullable input data.

@timeZones =
    EXTRACT Year int,
            DateFrom DateTime,
            DateTo DateTime,
            Offset int
    FROM "/Data/ESTTimeZones.csv"
    USING Extractors.Text(skipFirstNRows : 1, silent : true, quoting : false, delimiter : '\u0001');

@timeZones =
    SELECT Year,
           DateFrom,
           DateTo,
           ((int)(DateTo - DateFrom).TotalDays)) + 1 AS Days,    // Returns the total number of days covered by your date range
           Offset
    FROM @timeZones;

@timeZonesDays =
    SELECT t.Year,
           t.DateFrom,
           t.DateTo,
           t.Offset,
           d.JoinDate
    FROM @timeZones AS t
        CROSS APPLY EXPLODE(Enumerable.Range(0,t.Days)          // Creates a row for each day between each date range
                            .Select(n => t.DateFrom.AddDays(n))
                           ) AS d(JoinDate);

@output =
    SELECT p.createdon,
           p.createdon.AddHours(Offset) AS CreatedOn,
           t.Offset AS Offset
    FROM @partnerships AS p
        JOIN @timeZonesDays AS t
            ON p.createdonDate == t.JoinDate;

OUTPUT @output
TO "/Data/PartnershipwithOffset"
USING Outputters.Text(outputHeader : true, quoting : false, delimiter : '\u0001');

where子句的内容很大,但是对执行计划的影响很小。在我的数据库中运行时,此版本的代码大约需要45秒才能返回30天的时间跨度。

当我将两个联接分解为CTE时,例如:

Declare @from_date datetime = '4/1/2019'
,@to_date datetime = '4/30/2019'

select * from tableA  as a 
inner join tableB as b on b.c_id = a.c_id
inner join tableC as c on c.id = a.c_id
left JOIN tableD as d on d.user_id = a.user_id 
left JOIN tableE as e on e.id = c.e_id
left JOIN tableF as f on f.id = b.f_id
left JOIN tableG as g on g.id = c.g_id
left JOIN tableH as h on h.id = b.h_id
left JOIN tableI as i on a.id = i.a_id
where a.create_date between @from_date and @to_date
and b.valid_flag = convert(bit,1)

此版本将运行时间缩短到2秒,我认为这很棒。 现在,如果我将CTE转换为临时表,执行时间将跳至7秒,但是执行计划看起来更加编译。

与临时表实现查询相比,保留CTE会带来哪些风险?是否有值得增加5秒的缺点?如果您需要更多信息,请询问。感谢所有阅读过本文的人。

0 个答案:

没有答案