zoukankan      html  css  js  c++  java
  • 【原创】项目性能优化全纪录(一) 存储过程优化

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

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

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

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

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



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

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

     1 use CMS
    2 if Exists(select name from sysobjects where name='GetGroupClicksByDate' And type='p')
    3 drop procedure dbo.GetGroupClicksByDate
    4 go
    5
    6 create proc dbo.GetGroupClicksByDate
    7 @date_begin datetime,
    8 @date_end datetime,
    9 @int_interval int,
    10 @var_projectName varchar(32)
    11 as
    12 declare @int_datecount int
    13 if @date_begin is not null and @date_end is not null and @int_interval is not null and @var_projectName<>''
    14 begin
    15 set @int_datecount= datediff(hh,@date_begin,@date_end)
    16 if @int_datecount % @int_interval <>0
    17 set @date_end=DATEADD(HOUR, ((@int_datecount/@int_interval)+1)*@int_interval,@date_begin)
    18 select r.StartTime,r.EndTime, ISNULL(count(t.LogCode),0) as SumCount
    19 from applog t
    20 right join
    21 (
    22 select
    23 h.LogCode,
    24 DATEADD(HOUR,number*@int_interval,@date_begin) as StartTime,
    25 DATEADD(HOUR,(number+1)*@int_interval,@date_begin) as EndTime
    26 from master..spt_values,
    27 (select distinct LogCode
    28 from applog
    29 where applog.ProjectName=@var_projectName )h
    30 where type='P' and
    31 DATEADD(HOUR,(number+1)*@int_interval,@date_begin)<=@date_end
    32
    33 ) r
    34 on t.LogCode =r.LogCode and t.EventTime >= r.StartTime and t.EventTime< r.EndTime
    35
    36 group by r.StartTime,r.EndTime
    37 order by r.StartTime
    38 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了。旧项目里面还有很多东西需要考虑和优化,只有不断的优化才能使项目运行的更稳定才能使自己得到更大的提升,这就是“温故而知新”的重要意义吧。

  • 相关阅读:
    搭建MHA问题汇总
    NOIP2009 靶形数独
    get_mysql_conn_info.py
    NOIP 2005 篝火晚会
    MySQL启动关闭添加到 /etc/init.d/mysqld
    noip2002 矩形覆盖
    get_slave_status.py
    [JSOI2008]魔兽地图
    MySQL数据导出导入任务脚本
    8.30 牛客OI赛制测试赛1 F题 子序列
  • 原文地址:https://www.cnblogs.com/wangmingjin/p/2132238.html
Copyright © 2011-2022 走看看