方案A:declare @starttime datetime
declare @endtime datetime
set @starttime='2013-11-06'
set @endtime='2013-11-09' select a.ServerGroupId,a.PayTime as 日期,a.PayChannelID,
PayAmount 充值金额,PayAmount*10 as 充值元宝,ActualIngotCount-(PayAmount*10) 充值赠送元宝,
活跃用户数 as 活跃用户数,
付费用户数 as 付费用户数,
[付费次数] as [付费次数]
from 
(
select ServerGroupId as ServerGroupId,CONVERT(varchar(10),PayTime,120) as PayTime,PayChannelID,sum((PayAmount/100)) as PayAmount,COUNT(1) as [付费次数],count(distinct UserID) as 付费用户数,sum(ActualIngotCount) as ActualIngotCount  from T_UserPay where PayFlag=1 and PayTime>=@starttime and PayTime<@endtime   and ServerGroupId=4
group by ServerGroupId,CONVERT(varchar(10),PayTime,120),PayChannelID
) as a
left join
(
select ServergroupId,cid,日期,count(distinct UserID) as 活跃用户数 from View_ActiveUsers where 日期>=@starttime and 日期<@endtime group by ServergroupId,cid,日期
 ) as b
on a.ServergroupId=b.ServergroupId and a.PayChannelID=b.cid and a.PayTime=b.日期 
order by a.ServerGroupId asc,日期 asc
方案B:
declare @starttime datetime
declare @endtime datetime
set @starttime='2013-11-11'
set @endtime='2013-11-13' select ServerGroupId,CONVERT(varchar(10),PayTime,120) as PayTime,PayChannelID,sum((PayAmount/100)) as PayAmount,COUNT(1) as [付费次数],count(distinct UserID) as 付费用户数,sum(ActualIngotCount) as ActualIngotCount 
into #t1
 from T_UserPay where PayFlag=1 and PayTime>=@starttime and PayTime<@endtime   and ServerGroupId=4
group by ServerGroupId,CONVERT(varchar(10),PayTime,120),PayChannelID
select ServergroupId,cid,日期,count(distinct UserID) as 活跃用户数
into #t2
 from View_ActiveUsers where 日期>=@starttime and 日期<@endtime group by ServergroupId,cid,日期select 
a.ServerGroupId,a.PayTime as 日期,a.PayChannelID,
PayAmount 充值金额,PayAmount*10 as 充值元宝,ActualIngotCount-(PayAmount*10) 充值赠送元宝,
活跃用户数 as 活跃用户数,
付费用户数 as 付费用户数,
[付费次数] as [付费次数]
 from 
 
 #t1
 
  as a left join 
  
   #t2
   
    as b  
on a.ServergroupId=b.ServergroupId and a.PayChannelID=b.cid and a.PayTime=b.日期 
order by a.ServerGroupId asc,日期 asc
 drop table #t1
  drop table #t2
为什么方案B会比方案A的效率高出很多呢?
每个表数量都在千万条数据以上。
方案A执行了三分钟,还没出结果,方案B8秒钟时间。

解决方案 »

  1.   

    之所以方案B优于方案A,其实有很多原因:1.你方案A的语句,明显比B的复杂,这样不利于sql server产生比较优化的执行计划。
    那么你通过使用临时表,先把一个结果集计算出来,插入到临时表,然后再关联临时表,由于单个语句相对比较简单,后面临时表关联的语句,也比较简单,所以执行计划更优化,速度自然就快了。2.由于你没有及时更新表的统计信息,导致当你传入了各种参数后,sql server不能做出正确的执行计划,最后导致速度非常慢,这个时候,你可以通过更新统计信息,来让sql server做出正确的执行计划:update statistics 表
      

  2.   

    2个方案的@starttime不同,@endtime不同,返回的数据量也应该不同.
    跟数据分布情况,统计信息有关,建议对比一下2个的执行计划.
      

  3.   

    方案B是先通过where排除了大部分数据,然后再连接查询,这样笛卡尔乘积就小了很多,所以查询的时候效率更高。
    这是一个优化查询的技巧,当出现连接查询时,尽量减少笛卡尔乘积。