是的,表的数据量有些小,不过有控制1个数据页只能放下1行资料,所以尽管只有400行数据,也是占到400个datapage的。
如果有兴趣,可以insert 更多的资料再去试一下,不过我想这并没有多大影响。
结论……嗯,怎么说呢,
SELECT * FROM tb -- 一定会走 ROOT-->中间层(如果有)-->叶子层,数据是按聚集的主键排序SELECT * FROM tb WITH (NOLOCK) --->一定会从IAM 开始提扫描,数据是按物理存储的顺序读取,乱序。
至於为什么加上with (nolock)后会有这样的结果,我也不知道。
有经验的同学或是dba可以上来现身说法一下。
如果有兴趣,可以insert 更多的资料再去试一下,不过我想这并没有多大影响。
结论……嗯,怎么说呢,
SELECT * FROM tb -- 一定会走 ROOT-->中间层(如果有)-->叶子层,数据是按聚集的主键排序SELECT * FROM tb WITH (NOLOCK) --->一定会从IAM 开始提扫描,数据是按物理存储的顺序读取,乱序。
至於为什么加上with (nolock)后会有这样的结果,我也不知道。
有经验的同学或是dba可以上来现身说法一下。
--------
在哪儿控制的?
有一个这样的表: Employees (EmployeeID,EmployeeName,Sex,Birthday,PhotoFile, EnterDate, ProvinceID, CityID, Address, PostCode, IDCardNo) 。
其中EmployeeID为主键,并且按他建立了一个聚集索引PK_EmployeeID,在EmployeeName,Birthday,EnterDate,PostCode,IDCardNo上分别建立了非聚集索引IX_EmployeeName,IX_Birthday,IX_EnterDate,IX_PostCode,IX_IDCardNo。 如果我们用这样的一个语句进行查询:
Select * from Employees where EmployeeID=’C054965’
Select EmployeeID from Employees where EmployeeName=’刘永红’
则不会发生Book Lookup,而如果用下面的语句,则会发生Bookup Lookup:
Select Sex from Employees where EmployeeName=’刘永红’ 对照上面的语句,我们再回过头来看看照联机丛书中的解释。 “Book Lookup逻辑运算符和物理运算符使用书签(行 ID 或聚集键)在表或聚集索引内查找相应的行。” 对于语句 select Sex from Employees where EmployeeName=’刘永红’,服务器先在非聚集索引IX_EmployeeName上找到与“刘永红”对应的行定位器——“C054965”,然后根据这个值在聚集索引PK_EmployeeID上找到与“C054965”对应的数据行,并返回Sex——“男”这个值。而我们用select EmployeeID from Employees where EmployeeName=’刘永红’时,因为EmployeeID包含于聚集索引PK_EmployeeID的键值中,所以,不用再进行Book Lookup,而可以直接返回了。 但是对于select Sex from Employees where EmployeeName=’刘永红’ 就不同了,因为Sex并没有包含在PK_EmployeeID的键值中,也没有包含在EmployeeName的键值中,所以必须根据行定位器——“C054965”来进一步查找。 如果我们去掉聚集索引PK_EmployeeID,那么,服务器在执行Select Sex from Employees where EmployeeName=’刘永红’的时候,先在非聚集索引IX_EmployeeName上找到与“刘永红”对应的行定位器——指向EmployeeName=‘刘永红’的对应的数据行的指针,然后返回该行的Sex——“男”。 当然,如果我们执行select * from Employees where Sex=’男’,那么也不会发生Book Lookup,而是直接的表扫描(Table Scan)了,不管表Employees有没有建立聚集索引。 从这里,我们可以得出一些有趣的结论: 在一个聚集表上使用非聚集索引进行查询,其性能低于在堆集上使用非聚集索引进行查询。 查询性能比较:
返回行数较多:索引覆盖>聚集索引>表扫描>堆集的非聚集索引>聚集的非聚集索引
返回行数较少:索引覆盖=聚集索引>堆集的非聚集索引>聚集的非聚集索引>表扫描
所以,了解表的存储结构对于我们编写高效率的查询和建立高效率的索引有非常重要的意义。
通常情況下,在一個建有聚集索引的表上做Table Scan,速度是要慢於在堆表上的Table Scan。
當聚集索引的碎片很多時,在聚集表上做Table Scan速度要明顯快於Clustered index scan.
這個lz自己可以測試的到,將tb中的記錄數調到10000或是更多,然後再試。另外,在SQL2000中,加上With (Nolock)或是With (Tablock)后,走的是Table Scan.
SQL2005則有所改變,當聚集表的數據量小於64個Data Page,則不管是否加with nolock,走的是Clustered index scan. 大於64個Data Page才會走Table scan.
其中对于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