当我在CTE之前声明一个变量时,它需要大约5倍才能完成。我在SQL Server 2008 R2上。
我的数据库中的时间存储为Unix时间,因此我将一些变量从本地时间转换为Unix时间。现在我只包括Unix部分。积累是生产的总和,也是我使用CTE的原因。代码的以下部分大约需要5分钟才能执行。
Declare @StartTime bigint
Declare @EndTime bigint
declare @ticksPerDay bigint
Set @StartTime = 635330772000000000
set @EndTime = 635357556000000000
set @ticksPerDay = 864000000000
WITH MyCTE as
(SELECT ROW_NUMBER() OVER (ORDER BY CH.countercode, CH.Time ASC) AS
Sequence, CH.PlantCode, CH.CounterCode, CH.Time, CH.Accumulation
,DateAdd(mi, DATEDIFF(mi,getutcdate(), GetDate()),
DateAdd(d,Cast((CH.Time * Power(10.00000000000,-7)/60/60/24) as
int), CAST('0001-01-01' as Date)) + Cast(ch.Time *
Power(10.00000000000,-7)/60/60/24%1 as Datetime)) as LocalTime
FROM eit.CounterHist CH
INNER JOIN eit.CounterBasic cb on ch.CounterCode = cb.CounterCode
INNER JOIN eit.LineEquipment le on cb.PlantElementCode =
le.PlantElementCode
Where CH.Time>=@StartTime -(@ticksPerDay/24) and CH.Time<=@EndTime and
le.IsCriticalMachine = 1)
SELECT c1.PlantCode, c1.CounterCode, c1.time, c1.LocalTime,
COALESCE(c1.Accumulation - c2.Accumulation, 0) AS Prod
FROM MyCTE AS c1
Inner JOIN MyCTE AS c2 ON c1.Sequence = c2.Sequence + 1
Where c1.Time>=@StartTime and c1.Time<=@EndTime
order by c1.Sequence ASC;
另一方面,如果我只是将时间硬编码到where子句而不是使用变量,则运行大约需要1分钟。代码看起来如下(请查看where子句):
WITH MyCTE as
(SELECT ROW_NUMBER() OVER (ORDER BY CH.countercode, CH.Time ASC) AS
Sequence, CH.PlantCode, CH.CounterCode, CH.Time, CH.Accumulation,
DateAdd(mi, DATEDIFF(mi,getutcdate(), GetDate()),
DateAdd(d,Cast((CH.Time * Power(10.00000000000,-7)/60/60/24) as int),
CAST('0001-01-01' as Date)) + Cast(ch.Time *
Power(10.00000000000,-7)/60/60/24%1 as Datetime)) as LocalTime
FROM eit.CounterHist CH
INNER JOIN eit.CounterBasic cb on ch.CounterCode = cb.CounterCode
INNER JOIN eit.LineEquipment le on cb.PlantElementCode =
le.PlantElementCode
Where CH.Time>=635330772000000000 -(864000000000/24) and
CH.Time<=635357556000000000 and le.IsCriticalMachine = 1)
SELECT c1.PlantCode, c1.CounterCode, c1.time, c1.LocalTime,
COALESCE(c1.Accumulation - c2.Accumulation, 0) AS BottleCount
FROM MyCTE AS c1
Inner JOIN MyCTE AS c2 ON c1.Sequence = c2.Sequence + 1
Where c1.Time>=635330772000000000 and c1.Time<=635357556000000000
order by c1.Sequence ASC
有没有办法在CTE中使用局部变量或其他东西,因为在Unix时间输入很困难。
编辑:正面加载更多的代码(电源部分)并没有真正节省任何时间。我看到的大部分时间都在Where子句的CTE部分。
Where CH.Time>=@StartTime
Where CH.Time>=635330772000000000
当我使用@StartTime时,它需要的时间比第二个选项中的硬编码要长5倍。
我真的想避免硬编码,因为我希望能够输入正常日期,例如'2018-03-14 06:00:00'并转换为上述时间格式。
答案 0 :(得分:1)
查询优化器可以预先使用硬编码值做更多事情。
预先计算更多内容:
Declare @StartTime bigint = 635330772000000000
Declare @EndTime bigint = 635357556000000000
declare @ticksPerDay bigint = 864000000000
declare @StartTimeAdj bigint = @StartTime - (ticksPerDay / 24)
declare @pwr float = Power(10.00000000000,-7)/60/60/24
WITH MyCTE as
(SELECT ROW_NUMBER() OVER (ORDER BY CH.countercode, CH.Time ASC) AS Sequence
, CH.PlantCode, CH.CounterCode, CH.Time, CH.Accumulation
, DateAdd(mi, DATEDIFF(mi,getutcdate(), GetDate()), DateAdd(d,Cast((CH.Time * @pwr) as int), CAST('0001-01-01' as Date)) + Cast(ch.Time * @pwr%1 as Datetime)
) as LocalTime
FROM eit.CounterHist CH
INNER JOIN eit.CounterBasic cb on cb.CounterCode = ch.CounterCode
INNER JOIN eit.LineEquipment le on le.PlantElementCode = cb.PlantElementCode
Where CH.Time >= @StartTimeAdj
and CH.Time <= @EndTime
and le.IsCriticalMachine = 1
)
SELECT c1.PlantCode, c1.CounterCode, c1.time, c1.LocalTime,
COALESCE(c1.Accumulation - c2.Accumulation, 0) AS Prod
FROM MyCTE AS c1
Inner JOIN MyCTE AS c2 ON c1.Sequence = c2.Sequence + 1
Where c1.Time> = @StartTime and c1.Time <= @EndTime
order by c1.Sequence ASC;
我非常怀疑
Inner JOIN MyCTE AS c2 ON c1.Sequence = c2.Sequence + 1
你可以用铅或滞后来削减工作量半就
WITH MyCTE as
(SELECT lead(Accumulation) OVER (ORDER BY CH.countercode, CH.Time ASC) AS LeadAccumulation
, CH.PlantCode, CH.CounterCode, CH.Time, CH.Accumulation
, DateAdd(mi, DATEDIFF(mi,getutcdate(), GetDate()), DateAdd(d,Cast((CH.Time * @pwr) as int), CAST('0001-01-01' as Date)) + Cast(ch.Time * @pwr%1 as Datetime)
) as LocalTime
FROM eit.CounterHist CH
INNER JOIN eit.CounterBasic cb on cb.CounterCode = ch.CounterCode
INNER JOIN eit.LineEquipment le on le.PlantElementCode = cb.PlantElementCode
Where CH.Time >= @StartTimeAdj
and CH.Time <= @EndTime
and le.IsCriticalMachine = 1
)
SELECT c1.PlantCode, c1.CounterCode, c1.time, c1.LocalTime,
COALESCE(c1.Accumulation - c1.LeadAccumulation, 0) AS Prod
FROM MyCTE AS c1
Where c1.Time> = @StartTime and c1.Time <= @EndTime
order by c1.countercode, c1.Time ASC;
答案 1 :(得分:0)
当您将硬编码变量放入递归CTE时,数据结果会生成一次或进行优化,但如果您输入变量,CTE会重新生成多次。
考虑创建CTE语句的临时表。不要忘记在最后删除临时表。