优化日期之间的选择
Posted
技术标签:
【中文标题】优化日期之间的选择【英文标题】:Optimize selection between dates 【发布时间】:2018-08-12 23:38:33 【问题描述】:我的存储过程执行得非常糟糕。关于如何改进它的任何建议?
select t2.ID,
t2.Transactions,
t2.StartTime,
t2.EndTime,
t2.Good,
t2.OK,
t2.Bad,
t1.PID,
t1.PName
from(
select distinct ID,
max([PID]) as MaxPID,
min([DATE_S]) as StartTime,
max([DATE_S]) as EndTime,
count([ID_P]) as Transactions,
coalesce(count(case when [STATUS] = 0 then 1 end), 0) as Good,
coalesce(count(case when [STATUS] = 1 then 1 end), 0) as Warning,
coalesce(count(case when [STATUS] > 1 then 1 end), 0) as Bad
from [dbo].[Table1]
where CONVERT(date, [DATE_S]) between CONVERT(date, @StartDate) and
CONVERT(date, @EndDate)
group by ID) t2
LEFT join [dbo].[Table2] t1 on t2.MaxPID = t1.[PID]
order by ID desc
非常感谢任何提示。
【问题讨论】:
DISTINCT
超过 GROUP
ed 已经没有多大意义。另外,我怀疑COUNT()
是否按照您认为的方式工作。为此,您可能希望使用SUM()
。 (因为无论如何我都在使用它,所以使用t1
作为Table2
的别名有点令人困惑(反之亦然))
【参考方案1】:
几个假设 - 您的 @startdate 和 @enddate 是日期(没有时间组件),您的数据库记录是日期时间。还假设 date_s 上有一个索引,但它没有被使用,因为您没有直接在 where 子句中使用它。处理这个问题的方法是保留 date_s 原样,然后在你的 between 子句中使用 @startdate (这将是开始当天的午夜,@endDate+1 将是下一个午夜。
当然,这可能会从第二天开始在午夜开始的一行,如果是这种情况,则使用 next day-1second 或类似的东西。但不太可能成为问题。
where 子句:
where DATE_S between @StartDate and dateadd(d,1,@EndDate)
【讨论】:
实际上,午夜日期很可能是个问题。如果添加了任何没有时间的日期,则它们将显示为午夜。不要减去 1 秒,不要使用 between,而是使用 Where Date_S >= CONVERT(date, @StartDate) and Date_S @DancingFool 是的,取决于场景。就像我说的 - 做了一些假设!如果手动添加,则可能没有时间,如果在添加事务时自动添加,则不太可能。但是换成 >= 和 【参考方案2】:试试这样的:
declare @StartDateDt as datetime=cast(@StartDate as date);
declare @EndDateDt as datetime=cast(EndDate as date);
With tmp as (
select ID,
max(PID) as MaxPID,
min(DATE_S) as StartTime,
max(DATE_S) as EndTime,
count(ID_P) as Transactions,
sum(case when STATUS = 0 then 1 else 0 end) as Good,
sum(case when STATUS = 1 then 1 else 0 end) as Warning,
sum(case when STATUS > 1 then 1 else 0 end) as Bad
from dbo.Table1
where cast(DATE_S as date) between @StartDateDt and @EndDateDt
group by ID
)
select T2.*, T1.PID, T1.PName
from tmp T1
LEFT join dbo.Table2 T2 on T1.MaxPID = T2.PID
order by T1.ID desc
【讨论】:
【参考方案3】:select ID,
max([PID]) as MaxPID,
min([DATE_S]) as StartTime,
max([DATE_S]) as EndTime,
count([ID_P]) as Transactions,
coalesce(count(case when [STATUS] = 0 then 1 end), 0) as Good,
coalesce(count(case when [STATUS] = 1 then 1 end), 0) as Warning,
coalesce(count(case when [STATUS] > 1 then 1 end), 0) as Bad int #tmpResult
from [dbo].[Table1]
where CONVERT(date, [DATE_S]) between CONVERT(date, @StartDate) and
CONVERT(date, @EndDate)
group by ID
SELECT t2.ID,
t2.Transactions,
t2.StartTime,
t2.EndTime,
t2.Good,
t2.OK,
t2.Bad,
t1.PID,
t1.PName
FROM #tmpResult t2
LEFT join [dbo].[Table2] t1 on t2.MaxPID = t1.[PID]
order by ID desc
【讨论】:
distinct 和 group 不是必须的 ;)【参考方案4】:我假设[DATE_S]
包含datetime
值(日期和时间)
@StartDate
和 @EndDate
是日期时间数据类型,但仅包含日期值。
所以在@EndDate 中添加 1 天
set @EndDate=DateADd(day,1,@EndDate)
select t2.ID,
t2.Transactions,
t2.StartTime,
t2.EndTime,
t2.Good,
t2.OK,
t2.Bad,
t1.PID,
t1.PName
from(
select ID,
max([PID]) as MaxPID,
min([DATE_S]) as StartTime,
max([DATE_S]) as EndTime,
count([ID_P]) as Transactions,
coalesce(count(case when [STATUS] = 0 then 1 end), 0) as Good,
coalesce(count(case when [STATUS] = 1 then 1 end), 0) as Warning,
coalesce(count(case when [STATUS] > 1 then 1 end), 0) as Bad
from [dbo].[Table1]
where [DATE_S]>=@StartDate and [DATE_S]<=@EndDate
group by ID
) t2
LEFT join [dbo].[Table2] t1 on t2.MaxPID = t1.[PID]
order by ID desc
Create non Clustered index ix_Date on Table1(DATE_S)include(PID,ID_P,STATUS)
您可以告诉两个表的索引,以便相应地更正我的索引。
【讨论】:
以上是关于优化日期之间的选择的主要内容,如果未能解决你的问题,请参考以下文章