SQL Server 2014 在 where 子句中使用 DateAdd 来过滤巨大的 table
SQL Server 2014 Using DateAdd in where clause to filter huge table
我有两个 tables Meter
和 MeterSpot
。 Meter
table 有大约 9000 条记录,MeterSpot
有大约 7000 万条记录。 MeterID
列创建了两个 table 之间的关系。这是 table 设计的一部分:
Meter
: MeterID int, ContractHour int等......
MeterSpot
: MeterSpotID int, MeterID int, RecordStamp datetime, VolumeToday float 等......
我在 Meter.MeterID
和 MeterSpot.MeterSpotID
上有一个聚集索引,在 MeterSpot.RecordStamp
和 MeterSpot.MeterID
上有一个非聚集索引。
现在我需要从这两个 table 查询数据并获取 MeterID
、ContractDate
和 VolumeToday
列,其中 ContractDate
介于给定的日期范围。 ContractDate
的计算方法是从 MeterSpot
table 的 RecordStamp
中减去 Meter
table 的 ContractHour
。
这是我试过的:
SELECT
M.MeterID, MS.VolumeToday,
DATEADD(hour, -(M.ContractHour), MS.RecordStamp) AS 'ContractDate'
FROM
Meter AS M
INNER JOIN
MeterSpot AS MS ON M.MeterID = MS.MeterID
WHERE
(DATEADD(hour, -(M.ContractHour), MS.RecordStamp)
BETWEEN @StartDate and @EndDate)
执行此查询需要数小时。我搜索很少,发现当我在 where 子句上添加函数时,不考虑索引。
我在下面尝试过,对于较小的日期范围来说速度相当快。
WHERE MS.RecordStamp BETWEEN @StartDate AND @EndDate)
我试图将 ContractHour
添加到 @StartDate
和 @EndDate
而不是从 RecordStamp
中减去它。性能看起来还是一样。
问题:
- 如何过滤计算列中的数据?
- 我有更好的方法来完成我的任务吗?
- 在处理这种巨大的 table 时,我应该遵循哪些好的做法?
您可以提供两次日期条件,一次是告知 SQL 它可以如何利用其索引来加速您的查询,另一次是精确过滤出您需要的行。 ContractHour 是否有最大值?如果是这样,那么您可以这样做:
select ...
from Meter m
join MeterSpot ms on m.MeterID = ms.MeterID
where
(ms.RecordStamp between @StartDateMinusMaxContractHour and @EndDate)
and (dateadd(hour, -@m.ContractHour, ms.RecordStamp) between @StartDate and @EndDate)
我有两个 tables Meter
和 MeterSpot
。 Meter
table 有大约 9000 条记录,MeterSpot
有大约 7000 万条记录。 MeterID
列创建了两个 table 之间的关系。这是 table 设计的一部分:
Meter
: MeterID int, ContractHour int等......MeterSpot
: MeterSpotID int, MeterID int, RecordStamp datetime, VolumeToday float 等......
我在 Meter.MeterID
和 MeterSpot.MeterSpotID
上有一个聚集索引,在 MeterSpot.RecordStamp
和 MeterSpot.MeterID
上有一个非聚集索引。
现在我需要从这两个 table 查询数据并获取 MeterID
、ContractDate
和 VolumeToday
列,其中 ContractDate
介于给定的日期范围。 ContractDate
的计算方法是从 MeterSpot
table 的 RecordStamp
中减去 Meter
table 的 ContractHour
。
这是我试过的:
SELECT
M.MeterID, MS.VolumeToday,
DATEADD(hour, -(M.ContractHour), MS.RecordStamp) AS 'ContractDate'
FROM
Meter AS M
INNER JOIN
MeterSpot AS MS ON M.MeterID = MS.MeterID
WHERE
(DATEADD(hour, -(M.ContractHour), MS.RecordStamp)
BETWEEN @StartDate and @EndDate)
执行此查询需要数小时。我搜索很少,发现当我在 where 子句上添加函数时,不考虑索引。
我在下面尝试过,对于较小的日期范围来说速度相当快。
WHERE MS.RecordStamp BETWEEN @StartDate AND @EndDate)
我试图将 ContractHour
添加到 @StartDate
和 @EndDate
而不是从 RecordStamp
中减去它。性能看起来还是一样。
问题:
- 如何过滤计算列中的数据?
- 我有更好的方法来完成我的任务吗?
- 在处理这种巨大的 table 时,我应该遵循哪些好的做法?
您可以提供两次日期条件,一次是告知 SQL 它可以如何利用其索引来加速您的查询,另一次是精确过滤出您需要的行。 ContractHour 是否有最大值?如果是这样,那么您可以这样做:
select ...
from Meter m
join MeterSpot ms on m.MeterID = ms.MeterID
where
(ms.RecordStamp between @StartDateMinusMaxContractHour and @EndDate)
and (dateadd(hour, -@m.ContractHour, ms.RecordStamp) between @StartDate and @EndDate)