随笔-152  评论-346  文章-2  trackbacks-13

Top子句对查询计划的影响

1子查询的影响

Nest loop适用于被连接的数据

如果两个表做join操作,会有三种join方式: Nested join, Merge Join, Hash Join

Nested Join适用于结果集较小表

Hash Join适用于结果集很大的表

 

示例如下

create table moderatetable1(id int identity(1,1primary key, c1 int ,c2 int,c3 int,c4 int)
create table moderatetable2(id int identity(1,1primary key, c1 int ,c2 int,c3 int,c4 int)
declare @n int=0
while @n<100000
begin
    
insert moderatetable1(c1,c2,c3,c4) values(@n,@n,@n,@n)
    
insert moderatetable2(c1,c2,c3,c4) values(@n,@n,@n,@n)
    
set @n+=1
end

create index index1 on moderatetable1(C1)
create index index1 on moderatetable2(C2)
go
set statistics io on
select t1.c1 from moderatetable1 t1 inner join moderatetable2 t2
on t1.c1=t2.c1
go

 

下图是上面查询的执行计划和io统计信息

image

IO情况

(100000 行受影响)
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'moderatetable2'。扫描计数 1,逻辑读取 361 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'moderatetable1'。扫描计数 1,逻辑读取 176 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(1 行受影响)


 

如果只想取前50行,可以指定top 50:

select top 50 t1.c1 from moderatetable1 t1 inner join moderatetable2 t2
on t1.c1=t2.c1

image


(50 行受影响)
表 'moderatetable1'。扫描计数 50,逻辑读取 124 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'moderatetable2'。扫描计数 1,逻辑读取 2 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(1 行受影响)

 

我们看到,当指定了top 50之后,查询计划成了nested join.  当使用TOP时,SQLSEVER会认为这是一个较小的数据集,所以会使用nested join.对于这个查询,IO的开销比较李小. 但SQLSERVER经常会估计错误(即使统计信息是正确的).

我们看一下下面的查询:

select top 500 t1.c1 from moderatetable1 t1 inner join moderatetable2 t2
on t1.c1=t2.c1

 

image

(500 行受影响)
表 'moderatetable1'。扫描计数 500,逻辑读取 1080 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'moderatetable2'。扫描计数 1,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(1 行受影响)

返回行数增加到了500,SQLSERVER仍然使用nested join,得到了较差的IO

随着TOP的行数的增多,IO开销会越来越大. 但也不是总是这样,当top值达到一个临界点后,执行计划会变更成hash join.

select top 20000 t1.c1 from moderatetable1 t1 inner join moderatetable2 t2
on t1.c1=t2.c1

 

image


(20000 行受影响)
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'moderatetable2'。扫描计数 1,逻辑读取 74 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'moderatetable1'。扫描计数 1,逻辑读取 176 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(1 行受影响)

 

慎用TOP ...

标签: tunning
posted on 2011-06-14 11:02 stswordman 阅读(1508) 评论(10) 编辑 收藏

评论:
#1楼 2011-06-14 12:35 | huyong      
不错。支持支持。
 回复 引用 查看   
#2楼 2011-06-14 13:16 | superboyli      
楼主,多谢分享!您用什么工具分析的,分享一下!!!
 回复 引用 查看   
#3楼 2011-06-14 15:09 | 徐少侠      
@superboyli
应该是显示查询计划

 回复 引用 查看   
#4楼 2011-06-14 15:51 | wapco      
引用superboyli:楼主,多谢分享!您用什么工具分析的,分享一下!!!

用Sql Server自带的工具就有了。

 回复 引用 查看   
#5楼[楼主] 2011-06-14 16:11 | stswordman      
引用wapco:
引用superboyli:楼主,多谢分享!您用什么工具分析的,分享一下!!!

用Sql Server自带的工具就有了。

恩,工具栏上就有

 回复 引用 查看   
#6楼 2011-06-14 17:24 | icbj.cn      
收藏了
 回复 引用 查看   
#7楼 2011-06-15 08:28 | superboyli      
@wapco
多谢!!

 回复 引用 查看   
#8楼 2011-06-15 08:28 | superboyli      
@stswordman

多谢!

 回复 引用 查看   
#9楼 2011-06-16 13:49 | hukn      
create index index1 on moderatetable2(C2)

这个索引如果建立在C1字段上,结果就不太一样了

 回复 引用 查看   
#10楼[楼主] 2011-06-16 15:07 | stswordman      
引用hukn:
create index index1 on moderatetable2(C2)

这个索引如果建立在C1字段上,结果就不太一样了

如果c1上有索引,或者连接条件变为t1.c1=t2.c2
效果会好一些,
但仍然存在无法正确识别的区间。

 回复 引用 查看   
 
昵称:stswordman
园龄:5年11个月
粉丝:23
关注:0
<2011年6月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

常用链接

我的标签

随笔分类(252)

随笔档案(182)

相册

SQL

积分与排名

  • 积分 - 197955
  • 排名 - 431

最新评论

阅读排行榜

评论排行榜

推荐排行榜