我正在努力优化具有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秒的缺点?如果您需要更多信息,请询问。感谢所有阅读过本文的人。