深度探索:Clustered Index Scan  vs  Table Scan .
有帖子http://topic.csdn.net/u/20080704/11/40975992-fcce-4807-bd65-b65cc0b39e09.html
提到索引扫描的问题,其中关tb上只建有聚集索引时,select * from tb到底是走聚集索引还是走iam,
还是有些疑虑,所以做了以下的测试,有经验的同学可以发表下意见。
环境: SQL 2005+SP2 ON Winxp SP3
SQL code
1.
use tempdb
go
create table tb(a int primary key,b char(5000) default('bbbbb'))
go
declare @i int,@v int
set @i=1
while @i<=400
begin
reval:
    set @v=abs(checksum(newid())%1000)
    if exists(select * from tb where a=@v) 
        goto reval
    insert into tb(a) values (@v)
    set @i=@i+1
end
go
2.找出IAM、Root、IAM指向的第一页的页面位置
SQL code
select [first],[root],firstIAM,* from sysindexes where id=object_id('tb')
我这里的值分别如下图:
--
转换成十进制後,IAM页是1:90;IAM指向的第1个数据页是1:77;索引根页是1:110
3.计算分别从IAM开始扫描和从ROOT开始扫描所应该得出的结果
[3.1] 从ROOT页开始扫描(Clustered Index Scan)
	DBCC TRACEON(3604) --
	DBCC PAGE(tempdb,1,110,3) --查看索引根页的内容
     	结果如下图所示(图未截完) 
	记好ChildPageID的值,稍後要按row的顺序依次检查ChildPageID的内容(数据页)
	dbcc page(tempdb,1,434,1)
	结果如下图,转换成十进制之后,a的值是7,即select * from tb order by a 返回的
	第1行应该是7.
	如次再往下检查下一个ChildPageID的内容(1:434)
	并把检查a的结果记下来。
[3.2] 从IAM指向的第一页开始扫描(Table Scan)
	DBCC TRACEON(3604)
	DBCC PAGE(tempdb,1,90,3)--先查看iam页的内容,我的结果如下图
	依次检查下面的Slot 0~Slot 7所指数据页的内容,就是mssql扫描的顺序	
	1:77  a的值是355
	1:105 a的值是209
	1:121 a的值是210
	1:174 a的值是958
	......
4.验证	
[4.1]
SQL code
    SELECT * FROM TB WITH (NOLOCK)
/*    
a           b
----------- -----------
355         bbbbb      
209         bbbbb      
210         bbbbb      
958         bbbbb      
662         bbbbb      
490         bbbbb      
190         bbbbb      
101         bbbbb      
302         bbbbb      
51          bbbbb      
935         bbbbb      
630         bbbbb  
*/
a的顺序符合[3.2]所记录的值吧,说明此时走的是iam,即Table Scan !
[4.2]
SQL code
    SELECT * FROM TB 
/*
a           b
----------- ------------
7           bbbbb       
8           bbbbb       
9           bbbbb       
11          bbbbb       
13          bbbbb       
14          bbbbb       
15          bbbbb       
16          bbbbb       
17          bbbbb       
20          bbbbb       
21          bbbbb       
25          bbbbb       
26          bbbbb       
32          bbbbb       
33          bbbbb      
*/
可以见到a的值是有排序的,走的是聚集索引,结果应该是跟上面[3.1]记录的是一样.
5.结论
老实说,我被自己搞糊涂了。
我原本以为当聚集索引中的碎片很多时,SELECT * FROM tb 是会走iam扫描的,结果却不是,走的是索引扫描。
我用DBCC SHOWCONTIG(tb)查看索引碎片的值是98%,按理说不会去走index的,生成的执行计划
也是标了Ordered : FALSE(如下图),但我试了很多次,结果看起来都是按a排序的。
然后我就试着加上一些查询提示,WITH INDEX啊什么的,当试到WITH (NOLOCK)时,结果终於不一样
验证后发现with (NOLOCK)就是走的iam扫描.
打开set statistics io on ,
发现select * from tb with (nolock)比select * from tb 少读取1个io,应该是略过了根索引页。PS:下面的一段文字和图片都是来自於Inside SQL Server 2005这本书,说的是聚集索引扫描会走iam,这样看来是有问题的。
even though the execution plan shows a clustered index scan, the activity is no different than a table scan, and throughout the book I will often refer to it simply as a table scan. As shown in the illustration, here SQL Server will also use the index's IAM pages to scan the data sequentially. The information box of the Clustered Index Sca