我有一个SQL数据库和ASP.NET Web应用程序,我的大多数查询都涉及SQL max函数。
例如,以下查询介于约。在ASP.NET网站和SSMS上执行(使用分析器时)36秒。
SELECT MAX(CONVERT(FLOAT,ISNULL(Runhrs,Runho))) -
MIN(CONVERT(FLOAT,ISNULL(Runhrs,Runho))) AS ACTUALHOURSRUN
FROM REPORTINGSYSTEM.DBO.HL_LOGS
WHERE ID_LOCATION = @ID_LOCATION AND
CONVERT(VARCHAR,TIME_STAMP,102)
BETWEEN @STARTDATE AND @ENDDATE
有问题的表约有。 5,000,000条记录和45列。
执行查询以减少执行时间的最佳/最快/最有效的方法是什么?
提前致谢...
答案 0 :(得分:2)
ID_LOCATION和TIME_STAMP的索引将是一个不错的选择。
但是,当您将TIME_STAMP字段转换为VARCHAR时,这将阻止它能够使用索引。相反,重新编写查询以消除执行CONVERT的需要,而是使用DATETIME值。
e.g。
SELECT MAX(CONVERT(FLOAT,ISNULL(Runhrs,Runho))) - MIN(CONVERT(FLOAT,ISNULL(Runhrs,Runho))) AS ACTUALHOURSRUN
FROM REPORTINGSYSTEM.DBO.HL_LOGS
WHERE ID_LOCATION = @ID_LOCATION AND TIME_STAMP >= @STARTDATE AND TIME_STAMP < @ENDDATE
确保@STARTDATE和@ENDDATE也是DATETIME参数(我假设这是TIME_STAMP列的数据类型)
我还要问一下Runhrs / Runho列的数据类型是什么?如果没有存储为FLOAT / DECIMAL,那么它们可能不是最合适的数据类型吗?
答案 1 :(得分:1)
您需要做几件事:
ID_LOCATION
和TIME_STAMP
上的索引(如果您有其他查询按位置查询日期或按日期的位置,您可以考虑定义单独的索引;否则,单个组合索引将起作用。)@STARTDATE
和@ENDDATE
的原生数据类型,或将条件替换为TIME_STAMP between CONVERT(datetime,@STARTDATE) and CONVERT(datetime,@ENDDATE)
< / LI>
这两项更改应该会使您的查询更快,尤其是第二项更改:当前,CONVERT(VARCHAR,TIME_STAMP,102)
强制查询优化器对与您的位置匹配的所有内容进行完整扫描,如果没有索引则甚至进行全表扫描在ID_LOCATION
。索引搜索应该将记录数量降低到可接受的水平。
要采取的最后一项是CONVERT(FLOAT,ISNULL(Runhrs, Runho))
:如果前两次修改后的查询速度仍然不足,请将MAX(CONVERT(FLOAT,ISNULL(Runhrs,Runho)))
更改为CONVERT(FLOAT, MAX(ISNULL(Runhrs,Runho)))
,并对{{进行相同的更改1}}。这可能有效,也可能无效,具体取决于MIN
和Runhrs
的类型。
答案 2 :(得分:0)
首先,将Rhnhrs存储为数字类型。然后你不需要进行转换。
其次,您可以通过在hl_logs(id_location, time_stamp)
上创建索引来加快速度。你也可以抛出Runhrs
和Runho
。使用所有四列的索引(按此顺序),查询甚至不需要转到原始数据。
要使用索引,您需要将where
语句更改为:
time_stamp bewteen @startTimeStamp and @EndTimeStamp
如果变量是函数的参数,则SQL引擎将不使用索引。
生成的查询看起来应该更像:
select max(coalesce(runhrs, runho)) - min(coalesce(runhrs, runho) as Actual
from REPORTINGSYSTEM.DBO.HL_LOGS
WHERE ID_LOCATION = @ID_LOCATION AND
TIME_STAMP BETWEEN cast(@STARTDATE as datetime) AND cast(@ENDDATE as datetime)
答案 3 :(得分:0)
SELECT CONVERT(FLOAT, MAX(Runhrs)), CONVERT(FLOAT, MAX(Runho),
CONVERT(FLOAT, MIN(Runhrs)), CONVERT(FLOAT, MIN(Runho)
FROM REPORTINGSYSTEM.DBO.HL_LOGS
WHERE ID_LOCATION = @ID_LOCATION
AND TIME_STAMP BETWEEN @STARTDATE AND @ENDDATE
在调用SQL的代码中自己进行减法。 (那是.net代码。)
你应该在ID_LOCATION,TIME_STAMP,Runhrs,Runho上有一个索引。一个包含所有四个字段的索引。也许是两个指数。
CREATE INDEX REPORTINGSYSTEM.DBO.HL_LOGS ON ID_LOCATION, TIME_STAMP, Runhrs
CREATE INDEX REPORTINGSYSTEM.DBO.HL_LOGS ON ID_LOCATION, TIME_STAMP, Runho
答案 4 :(得分:0)
AND CONVERT(VARCHAR,TIME_STAMP,102)
这不是这样做的方法 - 它会导致缓慢。不要对DATA应用不必要的函数 - 它会使优化器无法使用此字段上的索引。反之亦然,将@STARTDATE
+ @ENDDATE
转换为与字段相同的数据类型。 (或者,按照这种方式考虑,你正在做5,000,000次转换,以便你可以比较2个变量)
[time_stamp] BETWEEN @STARTDATE AND @ENDDATE
请理解这实际上意味着:
[time_stamp] > = @STARTDATE AND [time_stamp] <= @ENDDATE
即。 BOTH&#34;边界&#34;日期时间包括在内,通常它更容易,更准确,以避免包容性,并拼写出来:
[time_stamp] > = @STARTDATE AND [time_stamp] < @ENDDATE (with @enddate
being "next day at 00:00:00:000)
MAX(CONVERT(FLOAT,ISNULL(Runhrs,Runho))) -
MIN(CONVERT(FLOAT,ISNULL(Runhrs,Runho))) AS ACTUALHOURSRUN
哇,这是很多函数调用!这里的问题并不纯粹MAX()/MIN()
。
建议您只需查看前面提到的Max(Runhrs)
等,然后进行减法。