FORM_TABLE表结构大致如下:
单号,  地区代码,时间1,时间2,  企业类型,单证类型,货物价值总计,税总计……
FORM_ID,AREA_CODE,TIME1,TIME2,CORP_TYPE,FORM_TYPE,VALUE_TOTAL,TAX_TOTAL……
   每一行有20多个字段,整个表有200多万行(只保留最近3个月数据)。表的主键是FORM_ID,已经建立了一个复合索引:包含AREA_CODE,TIME1,TIME2,CORP_TYPE字段。
    现在我需要做一个 “指定时间段内,各地区的单量总数”的统计功能。用到的存储过程功能大概如下:输入起始时间和截至时间(时间的判定以TIME1和TIME2的最小值为准),然后统计出每个地区的数据,数据包括单的总数(所有单,某一类型单),及货物价值总数,税总数。每次运算如果时间段比较大,查询的时间就很长。1个月的时间段查询大概要40多秒,2个月的话超过70秒,1天的话也要几秒钟。我写的存储过程大致如下,省略了输入参数和一些判断。各位高手帮忙看看,有什么地方可以优化的。输入参数:@time_begin , @time_endSELECT (case when AREA_CODE is not null then AREA_CODE else '总计' end) as AREA_CODE,
--单总数
SUM(CASE WHEN TIME1 is not null or  TIME2 is not null then 1 else 0 end) as TOTAL_COUNT,
--CORP_TYPE='1'的单总数
SUM(CASE WHEN CORP_TYPE='1' and  (TIME1 is not null or TIME2 is not null  )THEN 1 ELSE 0 END) as KX_COUNT ,
--CORP_TYPE='1'的单且。。的总数
SUM(CASE WHEN CORP_TYPE='1' and (TIME2 is null or FORM_TYPE='0') and  TIME1 is not null THEN 1 ELSE 0 END) AS NORMAL_COUNT,
--
SUM(TAX_TOTAL) AS TAX_SUM,
--总值
SUM(CASE WHEN CORP_TYPE='1' and (TIME1 is not null or TIME2 is not null  ) THEN VALUE_TOTAL ELSE 0 END) AS VALUE_SUM,
--税总值
SUM(CASE WHEN FORM_TYPE>'0' and CORP_TYPE='1' and TIME2 is not null THEN TAX_TOTAL ELSE 0 END) AS TAX_SUM
from FORM_TABLE 
WHERE (AREA_CODE between '1300' and '1399')  and ((case when TIME1>TIME2 or TIME1 is null then TIME2 else TIME1 end) between @time_begin and @time_end)
group by AREA_CODE
with ROLLUP
order by AREA_CODE

解决方案 »

  1.   

    --以下是在查询分析器里面的写法,看明白后,你存储过程就知道改怎么写了.
    --具体的统计没看,你自己更改.
    declare @time_begin as datetime
    declare @time_end as datetime
    declare @time_mid as datetime
    set @time_begin = '某个时间'
    set @time_end = '某个时间'
    --如果输入的时间大小搞混了,用个中间变量转换过来。
    if @time_begin > @time_end
       begin
         set @time_mid = @time_begin
         set @time_begin = @time_end
         set @time_end = @time_mid
       end
    select AREA_CODE , sum(VALUE_TOTAL) 货物价值总计, sum(TAX_TOTAL) 税总计 
    from table
    where 时间1 <= @time_begin and 时间2 >= @time_end
    group by AREA_CODE
      

  2.   

    /*
    try:应该不会有太大效果,太多的NULL判断、CASE,是比较耗时的。
    */--SELECT (case when AREA_CODE is not null then AREA_CODE else '总计' end) as AREA_CODE,
    SELECT isnull(AREA_CODE,'总计') as AREA_CODE,
    --单总数
    --SUM(CASE WHEN TIME1 is not null or TIME2 is not null then 1 else 0 end) as TOTAL_COUNT,
    SUM(CASE WHEN coalesce(TIME1,TIME2) is not null then 1 else 0 end) as TOTAL_COUNT,
    --CORP_TYPE='1'的单总数
    --SUM(CASE WHEN CORP_TYPE='1' and (TIME1 is not null or TIME2 is not null )THEN 1 ELSE 0 END) as KX_COUNT ,
    SUM(CASE WHEN CORP_TYPE='1' and coalesce(TIME1,TIME2) is not null THEN 1 ELSE 0 END) as KX_COUNT ,
    --CORP_TYPE='1'的单且。。的总数
    SUM(CASE WHEN CORP_TYPE='1' and (TIME2 is null or FORM_TYPE='0') and TIME1 is not null THEN 1 ELSE 0 END) AS NORMAL_COUNT,
    --
    SUM(TAX_TOTAL) AS TAX_SUM,
    --总值
    --SUM(CASE WHEN CORP_TYPE='1' and (TIME1 is not null or TIME2 is not null ) THEN VALUE_TOTAL ELSE 0 END) AS VALUE_SUM,
    SUM(CASE WHEN CORP_TYPE='1' and coalesce(TIME1,TIME2) is not null THEN VALUE_TOTAL ELSE 0 END) AS VALUE_SUM,
    --税总值
    SUM(CASE WHEN FORM_TYPE>'0' and CORP_TYPE='1' and TIME2 is not null THEN TAX_TOTAL ELSE 0 END) AS TAX_SUM
    from FORM_TABLE
    WHERE (AREA_CODE between '1300' and '1399') and ((case when TIME1>TIME2 or TIME1 is null then TIME2 else TIME1 end) between @time_begin and @time_end)
    group by AREA_CODE
    with ROLLUP
    order by AREA_CODE
      

  3.   

    经过分析发现,统计最耗时的是计算总值和税总值部分,如果不计算这部分数据,2个月的数据只需要一两秒就可以统计出来,但是一旦计算总值,耗时会达到40多秒。TAX_TOTAL 和 VALUE_TOTAL都是decimal(19,5)类型的,有没有什么办法加快统计的速度呢?
      

  4.   

    分别单独汇总TAX_TOTAL、VALUE_TOTAL看看。