一个 存储过程优化问题,百万条记录,大家帮忙看看 zjcxc(邹建)路过,进来指点一下
有表
TRecRecord(code(char(10)), bstype(char(2)),StepVolume(float),StepVal(float),StepVolume(int), StepVal(int) ,thedatetime (datetime) )
百万条记录,可能达到上千万
其中 code , thedatetime 做了索引
code , thedatetime 确定唯一记录
如下一个存储过程, 对code 的某一天进行统计
得到 最大,总数等, 现在统计功能很慢, 大家帮我分析一下看有没办法提高性能
ALTER proc pro_RecCount
--@Code int,
@Code char(10),
@bstype char(2),
@NewPrice float,
@thedatetime datetime
AS
declare
@MaxVol bigint,
@MaxStep float,
@RecCount int,
@TotalVol bigint,
@TotalStep float
select @MaxVol=max(StepVolume) ,@MaxStep=max(StepVal) , @RecCount=count(Code) , @TotalVol=sum(StepVolume) , @TotalStep= sum(StepVal)
from TRecRecord
where Code = @Code and bstype= @bstype and convert(char(25),thedatetime,112) = convert(char(25),@thedatetime,112)
------解决方案--------------------Try:
ALTER proc pro_RecCount
--@Code int,
@Code char(10),
@bstype char(2),
@NewPrice float,
@thedatetime datetime
AS
declare
@MaxVol bigint,
@MaxStep float,
@RecCount int,
@TotalVol bigint,
@TotalStep float
select @MaxVol=max(StepVolume) ,@MaxStep=max(StepVal) , @RecCount=count(Code) , @TotalVol=sum(StepVolume) , @TotalStep= sum(StepVal)
from TRecRecord
where Code = @Code and bstype= @bstype
and thedatetime> = convert(char(25),@thedatetime,112)
and thedatetime < dateadd(day,1,convert(char(25),@thedatetime,112))
go
另:加索引
(code,thedatetime,bstype)
------解决方案--------------------convert(char(25),thedatetime,112) = convert(char(25),@thedatetime,112)
使用函数的比较方法导致不能使用索引,是最大的问题
------解决方案--------------------个人看法:
1.对于查询一天的数据,如果查询的选择性已经比较高的话,
增加这个索引(code,thedatetime,bstype) 就没有什么意义了。
对于这样的查询:直接访问数据页,和查找索引然后书签查找数据 两者的i/o相差不大。
而且sql server更倾向于直接访问数据页的有序i/o,而不是书签查找的随机i/o
因为表的数据量可能会很大,增加索引要考虑磁盘和索引维护的因素
如果一定要修改,可以将 bstype 字段添加到clustered index 中就可以了
2.
--引用:
and thedatetime> = convert(char(25),@thedatetime,112)
and thedatetime < dateadd(day,1,convert(char(25),@thedatetime,112))
改成
@Starttime = convert(char(25),@thedatetime,112)
@Endtime = dateadd(day,1,convert(char(25),@thedatetime,112))
where thedatetime> = @Starttime
and thedatetime < @Endtime
我想性能肯定会提高很多....
------
恰恰相反,上面的写法效果会更好。
原因在于sql server在生成存储过程的执行计划(也可能是重新编译)时,是基于调用过程
所提供的input参数值。对于查询sql server是明确知道参数确切的值,会有助于sql server产生
有效的执行计划,但是如果是这样@Starttime ,@Endtime
这个就不是input参数了,是内部变量了,sql server在产生计划时是不知道它的值的。
你可以测试
第一种写法
如果选择性好的查询条件 clustered index seek
如果选择性差的查询条件 clustered index scan
对于第二种写法
应该都是clustered index scan
ps:为了测试时候不重用执行计划
2000: 过程级加上recompile
2005: 可以在语句级上加recompile
------解决方案--------------------问题出在条件过滤上,最慢的就是convert(char(25),thedatetime,112)部分
where Code = @Code and bstype= @bstype and convert(char(25),thedatetime,112) = convert