sqlserver开窗函数改造样例

作一个查询的性能优化。

先清缓存

DBCC DROPCLEANBUFFERS

DBCC FREEPROCCACHE

原查询 前人遗留。

 1 declare @total float,@total_person float,@times_person float,@date varchar(50) 
 2                         select @date=CONVERT(char(10),GETDATE(),120) 
 3 
 4                         select @total=sum(price*person)*1.0 from db_time t inner join db_movie m on t.movieid=m.id inner join db_cinema c on t.cinemaid=c.id 
 5                         where CAST(showdate as date)='2014-02-27' and t.sta=1 
 6 
 7                         select @times_person=sum(1)         from db_time t inner join db_movie m on t.movieid=m.id inner join db_cinema c on t.cinemaid=c.id
 8                         where CAST(showdate as date)='2014-02-27' and t.sta=1 
 9 
10                         select @total_person=sum(person)    from db_time t inner join db_movie m on t.movieid=m.id inner join db_cinema c on t.cinemaid=c.id
11                         where CAST(showdate as date)='2014-02-27' and t.sta=1 ;
12 
13                         with sr as(
14                         select 
15                         --ROW_NUMBER() over(order by SUM(price*person) desc) as 'index'
16                         --,
17                         movieid id
18                         ,m.name name                        
19                         ,m.enname 
20                         ,SUM(price*person)*1.0 as BoxOffice 
21                         ,SUM(price*person)*1.0/@total BoxPercent
22                         ,sum(1) ShowCount
23                         ,sum(1)*1.0/@times_person ShowPercent
24                         ,sum(person) AudienceCount
25                         ,sum(person)*1.0/@total_person AudiencePercent
26                         ,cast(round(sum(price*person)*1.0/sum(person),0) as int) Price 
27                         --,sum(person)*1.0/sum(1) as test
28                         --,sum(person)*1.0 as t1
29                         --,sum(1) as t2
30                         ,cast(round(sum(person)*1.0/sum(1),0) as int) as Renci
31                         ,round(CAST(sum(person) as float)/sum(seat),4) as Shangzl 
32                         from db_time t inner join db_movie m on t.movieid=m.id inner join db_cinema c on t.cinemaid=c.id
33                         where CAST(showdate as date)='2014-02-27' and t.sta=1 
34                         group by movieid,m.name,m.enname
35                         )
36 
37                         select * from sr order by BoxOffice desc

执行时间18S

最开始想着是把上面3条求总量的查询改成在一条里完成,where条件重复多次,想想开脆改成开窗函数好了

经开窗函数改造后的查询。

 1 with sr as(
 2                         select 
 3                         distinct
 4                         --ROW_NUMBER() over(order by SUM(price*person)  desc) as 'index'
 5                         --,
 6                         movieid id
 7                         ,m.name name                        
 8                         ,m.enname 
 9                         ,(SUM(price*person) OVER(PARTITION BY movieid))*1.0 as BoxOffice 
10                         ,(SUM(price*person) OVER(PARTITION BY movieid))*1.0/(SUM(price*person) OVER()) as BoxPercent
11                         ,sum(1) OVER(PARTITION BY movieid) as  ShowCount
12                         ,(sum(1) OVER(PARTITION BY movieid))*1.0/(sum(1) OVER()) ShowPercent
13                         ,sum(person) OVER(PARTITION BY movieid) AudienceCount
14                         ,((sum(person) OVER(PARTITION BY movieid))*1.0)/((sum(person) OVER())) AudiencePercent
15                         ,cast(round((sum(price*person) OVER(PARTITION BY movieid))*1.0/(sum(person) OVER(PARTITION BY movieid)),0) as int) Price 
16                         ,cast(round(((sum(person) OVER(PARTITION BY movieid))*1.0/(count(0) OVER(PARTITION BY movieid))),0) as int) as Renci
17                         ,round(CAST((sum(person) OVER(PARTITION BY movieid)) as float)/(sum(seat) OVER(PARTITION BY movieid)),4) as Shangzl 
18                         from db_time t inner join db_movie m on t.movieid=m.id inner join db_cinema c on t.cinemaid=c.id
19                         where CAST(showdate as date)='2014-02-27' and t.sta=1 
20                         )
21                         select * from sr order by BoxOffice desc

代码确实精简不少,同样的where子句消除了。(两个查询中的rownumber完全没用,注掉了)

执行时间17S,心里隐隐期待的是查询时间有明显减少,实际查询时间在误差范围内,基本未变化,看来开发开窗函数的目的不是为性能提升,而是为了方便开发人员编写查询代码,减少查询难度,提高查询可读性。

查询计划有很大变化,经开窗函数改造后的查询计划,多了很多“表假脱机”的执行步骤

但两种查询最耗时的依然是97%聚集索引扫描(表上只有id的自增聚集索引)

原文地址:https://www.cnblogs.com/zihunqingxin/p/3638857.html