MSSQL中的一些高级索引技术
Tags: MSSQLSQL Server优化索引压缩include索引WHERE索引过滤索引
简介
高级索引技术包括:
- INCLUDE索引
- 索引交叉:使用多个非聚集索引满足单个查询需要的所有列
- 索引连接:使用索引交叉和覆盖索引技术避免使用基础表
- 过滤索引:为在奇异分布或稀疏字段上创建索引,可以在索引上应用过滤,使得仅仅为某些数据创建索引
- 索引视图:这实现磁盘数据的视图输出
INCLUDE索引
创建测试表和测试数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | USER AdventureWorks; CREATE TABLE Member ( MemberNo INT IDENTITY, FirstName VARCHAR(30) NULL, LastName VARCHAR(30) NULL, EmailPromotion INT ); INSERT INTO Member(FirstName,LastName,EmailPromotion) SELECT FirstName,LastName,EmailPromotion FROM Person.Person; CREATE CLUSTERED INDEX clx_Member_No ON Member(MemberNo); CREATE NONCLUSTERED INDEX ix_Member_FirstName ON Member(FirstName); |
执行如下脚本,并查看执行计划和逻辑读情况
1 2 3 4 | SET STATISTICS IO ON; SELECT LastName,EmailPromotion FROM Member WHERE FirstName='Lolan'; |
由于非聚集索引ix_Member_FirstName仅仅包含FirstName列,EmailPromotion列没有包含在索引中,查询需要的数据需要从表中(聚集索引的叶)中获取,索引查询计划使用了键查找获取数据。
修改上面的非聚集索引,使其包含所有列,如下:
1 2 | CREATE NONCLUSTERED INDEX ix_Member_FirstName ON Member(FirstName) INCLUDE(LastName,EmailPromotion) WITH(DROP_EXISTING=ON); |
再执行查询,并查看结果:
可以看到,查询计划变为简单索引查找,逻辑读次数由原来的6次变为2次
INCLUDE最好的使用情景:
- 你不想增加索引键的大小,但是你想要索引变为覆盖索引
- 你想在一个不能创建索引的列上创建索引(text, ntext 和 images)
- 你已经超出了索引键列的最大列数(这种情况最好避免)
覆盖索引可以看做伪聚集索引
覆盖索引以序列顺序物理的组织所有索引数据。从磁盘I/O方面看,一个不使用包含列的覆盖索引,对于索引的列能完全满足查询情景来说,其变为一个聚集索引。如果查询结果集需要排序输出,那么覆盖索引可以按照结果集的需求,维持列的物理顺序和其一致。
建议
为利用覆盖索引的优点,注意SELECT后面的结果列。尽可能保证覆盖索引键列尽可能的小。使用INCLUDE增加列变得很有意义。因为覆盖索引包含查询中的所有列,它可能非常宽,增加维护覆盖索引的成本。你必须平衡维护成本和覆盖索引带来的性能优化。如果索引中所有列的字节数少于表中一行数据的字节,并且你确定采用覆盖索引的查询频繁的被执行,那么使用覆盖索引将非常有意义。
在创建大量的覆盖索引之前,考虑SQL Server 怎样有效的、自动的使用交叉索引,而非使用创建覆盖索引,使得查询飞起来。
交叉索引
如果表有多个索引,那么SQL Server 可能使用多个索引执行查询。SQl Server 可以利用多个索引的优点,选择基于每个索引较小的数据集,然后执行两个子集的交叉(即返回满足所有准则的行)。
SQL Server可以利用一个表上的多个索引,然后使用join算法获得两个表的交集。
在如下的查询语句中,WHERE条件列 SalesPersonID上没有非聚集索引,OrderDate列上没有索引: