索引这块从存储结构来分,有2大类,聚集索引和非聚集索引,而非聚集索引在堆表或者在聚集索引表都会对其 键值有所影响,这块可以详细查看本系列第二篇文章:SQL SERVER大话存储结构_(2)_非聚集索引如何查找到行记录。
非聚集索引内又分为多类:单列索引、复合索引、包含索引、过滤索引等。之前文章有具体分析过非聚集索引的存储情况,但是没有对复合索引及包含索引做过多说明,本文来讲讲这两个索引。
如果转载,请注明博文来源: www.cnblogs.com/xinysu/ ,版权归 博客园 苏家小萝卜 所有。望各位支持!
本系列上一篇博文链接:SQL SERVER大话存储结构(3)_数据行的行结构
--复合索引 CREATE INDEX IndexName ON tbname(columna,columnb [,columnc...] ) --包含索引 CREATE INDEX IndexName ON tbname(columna [,columnb,columnc...] ) INCLUDE (column1 [,column2,column3...])
复合索引,顾名思义,及多个列组成的索引,列的顺序非常重要,关系到查询性能,这点后面会说明。
包含索引,建索引SQL 中含有 include 字段,索引键值用于WHERE条件过滤,INCLUDE字段用于 SELECT 展示,这点后面也会说明。
无论是符合索引还是包含索引,都有索引键值长度不能超过900字节的限制,但是要注意一点,包含索引的include字段是不包括在里边的。
2 索引页存储情况
从索引页的存储情况来分析,分析过程中,重点在查看复合索引跟包含包含索引在 子节点及叶子结点的键值情况。
2.1 创建测试表格
创建表格 tbindex,建立两个测试索引,同时造数据。
1 CREATE TABLE tbindex( 2 id int identity(1,1) not null primary key , 3 name varchar(50) not null, 4 type varchar(10) not null, 5 numbers int not null 6 ) 7 GO 8 9 CREATE INDEX ix_number_name ON tbindex(numbers,name) 10 GO 11 CREATE INDEX ix_name ON tbindex(numbers) INCLUDE (name) 12 GO 13 14 DECLARE @ID INT 15 SET @ID=1 16 WHILE @ID<=5 17 BEGIN 18 INSERT INTO tbindex(name,type,numbers) 19 SELECT 20 name, 21 type, 22 object_id+@id 23 FROM sys.objects 24 25 SET @ID=@ID+1 26 END
2.2 分析索引行
--查看该表格索引的id情况 SELECT * FROM sys.indexes WHERE object_id=object_id('tbindex') --PK__tbindex__3213E83F89582AC3 1 --ix_number_name 2 --ix_number 3 DBCC traceon(3604) DBCC ind('dbpage','tbindex',-1) DBCC PAGE('dbpage',1,395,3) DBCC PAGE('dbpage',1,396,3) DBCC PAGE('dbpage',1,397,3) DBCC PAGE('dbpage',1,398,3)
分析查看,得知:
- 复合索引 IX_number_name的索引节点为pageid=395,再挑选一个叶子结点来分析 pageid=396;
- 包含索引 IX_number 的索引节点为 pageid=397,再挑选一个叶子节点来分析 pageid=398。
--复合索引,395为索引页节点,396为索引页叶子节点
DBCC PAGE('dbpage',1,395,3)
DBCC PAGE('dbpage',1,396,3)
--包含索引,397为索引页节点,398为索引页叶子节点
DBCC PAGE('dbpage',1,397,3)
DBCC PAGE('dbpage',1,398,3)
从这里可以看出,复合索引跟包含索引的 所有索引列都会存储在索引叶子节点跟子节点,但是包含索引 的INCLUDE列,不在索引页的子节点存储,仅存储在 索引页的叶子节点上。
从这里不难理解,为什么之前说 include列用于 select 列,而不用于 where 列过滤。因为非聚集索引当索引页面有多层的时候,是先查询 索引的子节点,再查询索引的叶子节点,而包含索引的INCLUDE列不在叶子节点中存储,无法根据其来进行过滤。
3 对查询的影响
3.1 复合索引查询注意事项
由于需要数据量作为实验支持,所以不用之前分析索引行结构的表格tbindex,换个高大上 tb_composite 如下。
1 create table tb_composite( 2 id int identity(1,1) not null primary key, 3 name varchar(50) not null, 4 userid int not null, 5 timepoint datetime not null 6 ) 7 GO 8 9 create index ix_userid_name on tb_composite(userid,name) 10 GO 11 12 create index ix_userid on tb_composite(userid) 13 GO 14 15 INSERT INTO tb_composite(name,userid,timepoint) 16 SELECT 17 newid(),orderid%10000 ,CreatedDate 18 FROM ORDERS