日期:2014-05-18  浏览次数:20490 次

一个 存储过程优化问题,百万条记录,大家帮忙看看 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