处理SQL问题并且我不是SQL人员,因此需要一些指导。
鉴于下面的SQL语句,请注意第一个在DateAdd函数中使用硬编码值“-360”,而第二个使用每个记录上存在的字段值(OFFSET)(其值为“-360”或“-300”取决于DST时间。)
运行第一个查询非常快,而第二个查询需要大约40秒。
有人可以告诉我,执行第二次这么长时间的区别是什么,因为我必须使用该记录的值而不是硬编码,我怎样才能加快查询速度?
查询1(快速):
SELECT 0 AS 'TempIndex', COUNT(*) AS 'TotalLY'
FROM CLOGS15 h
WHERE h.EVTYPE = 1
AND DateAdd(minute, -360, h.EVDATE) BETWEEN '2015-01-01 00:00:00.000' AND '2015-01-24 00:00:00.000'
查询2(SLOW):
SELECT 0 AS 'TempIndex', COUNT(*) AS 'TotalLY'
FROM CLOGS15 h
WHERE h.EVTYPE = 1
AND DateAdd(minute, OFFSET, h.EVDATE) BETWEEN '2015-01-01 00:00:00.000' AND '2015-01-24 00:00:00.000'
答案 0 :(得分:2)
我只能想象问题是sargability(索引的用户)。但是,我认为dateadd()
会阻止使用索引。如果你想解决这个问题,也许这会有效:
SELECT 0 AS TempIndex, COUNT(*) AS TotalLY
FROM CLOGS15 h
WHERE h.EVTYPE = 1 AND offset = 360 AND
DateAdd(minute, -360, h.EVDATE) BETWEEN '2015-01-01' AND '2015-01-24'
UNION ALL
SELECT 0 AS TempIndex, COUNT(*) AS TotalLY
FROM CLOGS15 h
WHERE h.EVTYPE = 1 AND offset = 300 AND
DateAdd(minute, -300, h.EVDATE) BETWEEN '2015-01-01' AND '2015-01-24';
编辑:
糟糕,上面返回两行,你想要一行。所以,使用子查询:
SELECT TempIndex, SUM(TotalLY) as TotalLY
FROM (SELECT 0 AS TempIndex, COUNT(*) AS TotalLY
FROM CLOGS15 h
WHERE h.EVTYPE = 1 AND offset = 360 AND
DateAdd(minute, -360, h.EVDATE) BETWEEN '2015-01-01' AND '2015-01-24'
UNION ALL
SELECT 0 AS TempIndex, COUNT(*) AS TotalLY
FROM CLOGS15 h
WHERE h.EVTYPE = 1 AND offset = 300 AND
DateAdd(minute, -300, h.EVDATE) BETWEEN '2015-01-01' AND '2015-01-24'
) h
GROUP BY TempIndex;
答案 1 :(得分:0)
在您的情况下,我认为快速和慢速查询之间的区别在于索引的使用。
快速查询中的SQL Server可能会重写您的DATEADD
以启用EVDATE
上的索引使用。当您添加日期和常量并检查它是否在常量日期之间时,它可能会将DATEADD
从左侧(BETWEEN
之前)移动到右侧(之后的日期) BETWEEN
,反转DATEADD
中常量的信号。
您的原件是:
DateAdd(minute, -360, h.EVDATE)
BETWEEN '2015-01-01 00:00:00.000'
AND '2015-01-24 00:00:00.000'
可能会转向:
h.EVDATE
BETWEEN DateAdd(minute, 360, '2015-01-01 00:00:00.000')
AND DateAdd(minute, 360, '2015-01-24 00:00:00.000')
这与原始过滤器相同,但启用了DATEADD
的索引使用和处理,因为只需要处理两个日期,而不是表格中的所有日期。
在慢速查询中,由于DATEADD
正在使用变量偏移量,因此SQL Server无法应用上述相同规则,因此它会使用DATEADD
处理表格中的所有日期,这真的很慢。
我认为您应该尝试像快速查询这样的过滤器,可能是这样的:
SELECT 0 AS 'TempIndex', COUNT(*) AS 'TotalLY'
FROM CLOGS15 h
WHERE 1=1
AND h.EVTYPE = 1
AND
(0=1
OR
(1=1
AND OFFSET = -360
AND h.EVDATE >= DateAdd(minute, 360, '2015-01-01 00:00:00.000')
AND h.EVDATE <= DateAdd(minute, 360, '2015-01-24 00:00:00.000')
)
OR
(1=1
AND OFFSET = -300
AND h.EVDATE >= DateAdd(minute, 300, '2015-01-01 00:00:00.000')
AND h.EVDATE <= DateAdd(minute, 300, '2015-01-24 00:00:00.000')
)
)
查询分别包含EVTYPE
,OFFSET
,EVDATE
列的索引会很棒。