为什么在创build索引时使用INCLUDE子句?
在参加70-433考试时,我注意到您可以通过以下两种方式之一创build一个覆盖指数。
CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)
– 要么 –
CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)
INCLUDE子句对我来说是新的。 为什么要使用它,以及在确定是否创build一个包含INCLUDE子句的覆盖索引时,您会提出哪些build议?
如果该列不在WHERE / JOIN / GROUP BY / ORDER BY中,但仅在SELECT子句的列列表中。
INCLUDE子句在最低/叶级别添加数据,而不是在索引树中。 这使索引更小,因为它不是树的一部分
这意味着它不是像上面提到的那样对谓词,sorting等有用。 但是,如果您在关键列的几行中有剩余查找,
另一个MSDN文章与一个工作的例子
您可以使用INCLUDE将一个或多个列添加到非聚集索引的叶级别,如果这样做,则可以“覆盖”查询。
想象一下,您需要查询员工的ID,部门ID和姓氏。
SELECT EmployeeID, DepartmentID, LastName FROM Employee WHERE DepartmentID = 5
如果你碰巧有一个非聚集索引(EmployeeID,DepartmentID),一旦你find给定部门的雇员,你现在必须做“书签查找”来获得实际的完整员工logging,只是为了得到姓氏列。 如果你find很多员工,那么在性能方面可能会相当昂贵。
如果您在索引中包含姓氏:
CREATE NONCLUSTERED INDEX NC_EmpDep ON Employee(EmployeeID, DepartmentID) INCLUDE (Lastname)
那么您需要的所有信息都可以在非聚集索引的叶级别中使用。 只需要在非聚集索引中find给定部门的员工,就可以获得所有必要的信息,并且不再需要在索引中find的每个员工的书签查找 – >您可以节省大量时间。
很明显,你不能在每个非聚集索引中包含每一列 – 但是如果你确实有一些只有一列或两列没有被查询的查询被“覆盖”(并且被大量使用),那么INCLUDE变成一个合适的非聚集索引。
基本索引列是sorting的,但包含的列不会sorting。 这节省了维护索引的资源,同时仍然可以在包含的列中提供数据来覆盖查询。 因此,如果您想要涵盖查询,则可以将search条件定位到索引的已sorting列中,然后“包含”具有非search数据的其他未sorting列。 这绝对有助于减less索引维护中的分类和碎片数量。
这个讨论在重要的问题上被忽略了:问题不在于如果“非键列”更好地包含为索引 – 列或包含 –列。
问题是使用include-mechanism包含索引中不真正需要的列是多么昂贵? (通常不是where子句的一部分,但通常包含在select中)。 所以你的困境总是:
- 单独使用id1,id2 … idN的索引
- 使用id1,id2 … idN plus的索引, 包括 col1,col2 … colN
其中:id1,id2 … idN是限制中经常使用的列,col1,col2 … colN是经常select的列,但通常不用于限制
(包含所有这些列作为索引键的一部分的选项总是愚蠢的(除非它们也用于限制) – 因为索引必须更新和sorting, “钥匙”没有改变)。
那么使用选项1或2?
答案:如果你的表很less被更新 – 大部分是插入/删除的 – 那么使用include-mechanism包含一些“热列”(通常用在select中,但在限制上不常用)插入/删除要求索引被更新/sorting,因此在更新索引的同时,less量额外的开销与存储一些额外的列相关联。 开销是用于在索引上存储冗余信息的额外内存和CPU。
如果您认为要添加为包含列的列经常更新(没有更新索引键列), 或者如果索引中的索引越来越接近表副本,则使用选项1我build议! 另外,如果添加某些include-column(s)会导致没有性能差异 – 您可能想跳过添加它们的想法:)确认它们是有用的!
键(id1,id2 … idN)中每个相同值的平均行数也可能具有一定的重要性。
请注意,如果在限制中使用了作为索引的包含列添加的列: 只要可以使用索引 (基于对索引键列的限制),则SQL Server匹配对索引(叶节点值)的列限制,而不是在表本身周围花费昂贵的方式。
(包括指数叶级数据)的原因已经得到了很好的解释。 之所以这样做,是因为在运行查询时,如果没有包含附加列(SQL 2005中的新function),SQL Server必须转到聚集索引以获取其他列这需要花费更多的时间,并且随着新的数据页面被加载到内存中,将更多的负载添加到SQL Server服务,磁盘和内存(缓冲区高速caching是特定的),可能将更经常需要的数据推出缓冲区高速caching。
在已经给出的答案中还没有看到额外的考虑,其中包括的列可以是不允许作为索引键列的数据types,如varchar(max)。
这使您可以将这些列包含在覆盖索引中。 我最近不得不这样做来提供一个nHibernate生成的查询,这个查询在SELECT中有很多列,并且有一个有用的索引。
内联到索引定义中的所有列的总大小是有限制的。 尽pipe如此,我从来没有必要创build索引。 对我来说,更大的好处是可以用一个包含列的索引覆盖更多的查询,因为它们不需要按照任何特定的顺序来定义。 考虑一下是作为索引内的索引。 例如,StoreID(StoreID的select性较低,意味着每个商店都与很多客户关联),然后是客户人口统计数据(LastName,FirstName,DOB):如果您只是按此顺序内联这些列(StoreID,LastName ,FirstName,DOB),只能有效地search您知道StoreID和LastName的客户。
另一方面,在StoreID上定义索引,包括LastName,FirstName,DOB列将使您在本质上在StoreID上执行两个search索引谓词,然后在任何包含的列上查找谓词。 这可以让你涵盖所有可能的search排列,只要它以StoreID开头。