深度探索: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 tempdbgocreate table tb(a int primary key,b char(5000) default('bbbbb'))godeclare @i int,@v intset @i=1while @i<=400beginreval: 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+1endgo
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 Scan operator tells you that the scan was not ordered, meaning that the access method did not rely on the linked list that maintains the logical order of the index.
[解决办法]
先顶后看
[解决办法]
[解决办法]
嘿嘿,终于验证了我的思路。
[解决办法]
看看,,,
[解决办法]
来过
[解决办法]
学习
[解决办法]
学习.楼主辛苦
[解决办法]
看看
,,,,
[解决办法]
[解决办法]
up
[解决办法]
加上With (Nolock)后,意思是指告SQLServer不在乎到一些(未提交的),所以用分配元的描是更好的。
通常情下,在一建有聚集索引的表上做Table Scan,速度是要慢於在堆表上的Table Scan。
聚集索引的碎片很多,在聚集表上做Table Scan速度要明快於Clustered index scan.
lz自己可以的到,tb中的到10000或是更多,然後再。
另外,在SQL2000中,加上With (Nolock)或是With (Tablock)后,走的是Table Scan.
SQL2005有所改,聚集表的量小於64Data Page,不管是否加with nolock,走的是Clustered index scan. 大於64Data Page才走Table scan.
[解决办法]
学习了
[解决办法]
看看
[解决办法]
mark
[解决办法]
学习了
[解决办法]
在《Inside Microsoft SQL Server 2005 T-SQL Querying》一书中,作者讲解了Index Access Methods。
其中对于Unordered Clustered Index Scan的讲解确实是有不正确的地方,正如楼主所迷惑的。
此书出版不久,作者就在他的Blog上重新阐述了这个问题。
参考:
Quaere Verum - Clustered Index Scans - Part I
http://www.sqlmag.com/Article/ArticleID/92886/sql_server_92886.html
Quaere Verum - Clustered Index Scans - Part II
http://www.sqlmag.com/Article/ArticleID/92887/sql_server_92887.html
Quaere Verum - Clustered Index Scans - Part III
http://www.sqlmag.com/Article/ArticleID/92888/sql_server_92888.html
[解决办法]
强文,收藏一下。
[解决办法]
学习了。