您的位置:首页 > 其它

【原创】项目性能优化全纪录(一) 存储过程优化

2011-08-09 14:24 225 查看
公司的项目中需要增加一个对信息亭点击量进行实时统计的子项目。前台程序点击的Log数据会被保存到服务器上的一张AppLog表中。

信息亭每天的点击量很高,可想而知AppLog表中数据量得有多大。据初步估算,一年可以产生上亿条点击纪录。因而数据统计的性能问题一直困扰着我。

七夕节在家没事干,就看了一下微软的WebCast中asp.net优化的那部分视频同时还看了一本Richhard Kiessing写的《构建高性能可扩展Asp.net网站》。

星期一一上班就开始着手对项目进行优化。

废话不多说先看Applog的表结构:



所作的统计基本上都是根据EventTime来统计Logcode的数量。其中有一个最耗费性能的统计就是根据某一个时间段按照用户给出的统计条件来统计点击数量。

项目第一个版本的存储过程是这样写的:

use CMS
if Exists(select name from sysobjects where name='GetGroupClicksByDate' And type='p')
drop procedure dbo.GetGroupClicksByDate
go

create proc dbo.GetGroupClicksByDate
@date_begin datetime,
@date_end datetime,
@int_interval int,
@var_projectName varchar(32)
as
declare @int_datecount int
if @date_begin is not null and @date_end is not null and @int_interval is not null and @var_projectName<>''
begin
set @int_datecount= datediff(hh,@date_begin,@date_end)
if  @int_datecount % @int_interval <>0
set @date_end=DATEADD(HOUR, ((@int_datecount/@int_interval)+1)*@int_interval,@date_begin)
select r.StartTime,r.EndTime, ISNULL(count(t.LogCode),0) as SumCount
from applog t
right join
(
select
h.LogCode,
DATEADD(HOUR,number*@int_interval,@date_begin) as StartTime,
DATEADD(HOUR,(number+1)*@int_interval,@date_begin) as EndTime
from master..spt_values,
(select distinct LogCode
from applog
where applog.ProjectName=@var_projectName )h
where type='P' and
DATEADD(HOUR,(number+1)*@int_interval,@date_begin)<=@date_end

) r
on t.LogCode =r.LogCode and t.EventTime >= r.StartTime and t.EventTime< r.EndTime

group by r.StartTime,r.EndTime
order by r.StartTime
end


  其原理是通过master数据库生成一张时间段的临时表,然后再利用Applog表和master表进行右连接之后,在进行分组统计查询。

我统计一次从2010年1月1日到2011年11月2日,SQLServer执行的时间是1分51.555秒。结果如下:



通过思考,我发现可以先根据时间段来拆分SQL语句,然后使用union all在连接起来查询,这样的话可以减少运算3次笛卡尔积性能必定能够提升。其具体实现如下:

use CMS
if Exists(select name from sysobjects where name='GetGroupClicksByDate' And type='p')
drop procedure dbo.GetGroupClicksByDate
go
/*
Written By:WMJ
WriteDate :2011-08-19
Function: Get the clicks by time interval
*/
create proc dbo.GetGroupClicksByDate
@date_begin datetime,
@date_end datetime,
@int_interval int,
@var_projectName varchar(32)
as

declare @var_SQL varchar(MAX)
declare @int_datecount int
declare @int_datecal int
declare @date_temptime datetime
if @date_begin is not null and @date_end is not null and @int_interval is not null and @var_projectName<>''
begin
set @int_datecount= datediff(hh,@date_begin,@date_end) --Calcultate the total hours count
set @int_datecal=@int_datecount/@int_interval          --Calculate the total datarangge count
if  @int_datecount % @int_interval <>0
begin
set @date_end=DATEADD(HOUR, ((@int_datecount/@int_interval)+1)*@int_interval,@date_begin)
end
set @date_temptime=DATEADD(HOUR,@int_interval,@date_begin)
set @var_SQL='select count(*) as Sumcount,'''+CONVERT(varchar, @date_begin,120)+''' as StartTime,'''+CONVERT(varchar,@date_temptime ,120)+''' as EndTime from applog where applog.EventTime> '''+CONVERT(varchar, @date_begin,120)
set @date_begin=@date_temptime
set @var_SQL=@var_SQL+ ''' and applog.EventTime <='''+CONVERT(varchar, @date_begin ,120)+''' and applog.ProjectName= '''+@var_projectName+''' '
while @int_datecal>0
begin

set  @date_temptime=DATEADD(HOUR,@int_interval,@date_begin)
set @var_SQL=@var_SQL+' union all '+' select count(*) as Sumcount,'''+CONVERT(varchar, @date_begin,120)+''' as StartTime,'''+Convert(varchar,@date_temptime,120)+''' as EndTime from applog where applog.EventTime> '''+CONVERT(varchar, @date_begin,120)
set @date_begin=@date_temptime
set @var_SQL=@var_SQL+ ''' and applog.EventTime <='''+CONVERT(varchar, @date_begin ,120)+''' and applog.ProjectName= '''+@var_projectName+''' '
set @int_datecal=@int_datecal-1
end
end
exec( @var_SQL)--Exexute the sql


  事实证明我的想法是对的,执行同样的查询得到相同的结果SQL Server只需要1.319秒,性能提升了98.82%.如下图所示:



通过这次成功的优化,我发现做写程序做项目不仅仅是把项目完成就OK了。旧项目里面还有很多东西需要考虑和优化,只有不断的优化才能使项目运行的更稳定才能使自己得到更大的提升,这就是“温故而知新”的重要意义吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: