您的位置:首页 > 博客中心 > 数据库 >

SQL Server 非聚集索引的覆盖,连接,交叉和过滤 <第二篇>

时间:2022-03-15 05:15

  在SQL Server中,非聚集索引其实可以看做是一个含有聚集索引的表,但相对实际的表来说,非聚集索引中所存储的表的列数要少得多,一般就是索引列,聚集键(或RID)。非聚集索引仅仅包含源表中的非聚集索引的列和指向实际物理表的指针。

  此表大约是15万数据左右。聚集索引列是Id,我们先来在Name列建立一个非聚集索引。

  CREATE NONCLUSTERED 
  INDEX Index_Name ON Person(Name)

  然后执行查询:

  SELECT Name,Age FROM Person where Name = ‘欧琳琳‘

  执行计划如下:

  技术分享

  上面的执行过程是,先扫描非聚集索引列,找到聚集索引,然后在通过聚集索引定位到数据。

  下面我们删除掉刚才那个索引,再建过另外一个。

  DROP INDEX Person.Index_Name    --删除非聚集索引Index_Name

  CREATE NONCLUSTERED             --再重新建过一次,这次我们INCLUDE Age列
  INDEX Index_Name ON Person(Name)
  INCLUDE (Age)

  现在我们再来看看刚才的查询的执行计划:

  技术分享

  由于Age列也被INCLUDE进了非聚集索引INDEX_Name中,因此这次仅仅通过查找非聚集索引就能够得到所需的全部数据。不需要再扫描聚集索引了。明显这次查询要比刚才快。

  要注意的是INCLUDE进来的列,并不作为索引使用,能当索引扫描的,只是索引列

  INCLUDE最好在以下情况中使用:

  • 你不希望增加索引键的大小,但是仍然希望有一个覆盖索引;
  • 你打算索引一种不能被索引的数据类型(除了文本、ntext和图像);
  • 你已经超过了一个索引的关键字列的最大数量(但是最好避免这个问题);

   可以看到,也是仅仅查找了非聚集索引就得到了结果。效率非常快。

  下面来看看覆盖和前面的INCLUDE有什么区别呢?我们将搜索条件改为Age。

   覆盖索引:

  技术分享

  INCLUDE:

  技术分享

  留意一下,INCLUDE是聚集表扫描了,而覆盖索引依然使用非聚集索引就找到了结果。

  因此可以得出结论,INCLUDE列并不能当索引键使用。

  为了利用覆盖索引,要注意SELECT语句的清单,应尽可能使用较少的列来保持小的覆盖索引的尺寸,使用INCLUDE语句来添加的列这时候才有意义。

  在建立许多覆盖索引之前,考虑SQL Server如何有效和自动地使用索引交叉来为查询即时创建覆盖索引。

  非聚集索引的本质是表,通过额外建立表使得几个非聚集索引之间进行像表一样的Join,从而使非聚集索引之间可以进行Join来在不访问基本表的情况下给查询优化器提供所需要的数据。

  为了增进一个查询的性能,SQL Server可以在表上使用多个索引。因此,考虑创建多个窄索引来代替宽的索引键。SQL Server能够在需要的时候一起使用它们,当不需要时,查询可以从窄索引中获益。在创建一个覆盖索引时,需要确定索引的宽度是否可以接受,使用包含列是否可以完成任务。如果不行则确定现有的包含大部分覆盖索引所需要的列的非聚集索引。如果有可能,适当重新安排现有非聚集索引的列顺序,使优化器能够考虑两个非聚集索引之间的的一个索引交叉。

  有时候,可能必须为一下原因创建一个单独的非聚集索引:

  •   重新排列现有索引中的列不被允许;
  •   覆盖索引所需要的一些列不能被包含在现有的非聚集索引中;
  •   两个现有非聚集索引中的总列数可能多于覆盖索引所需要的列数;

  在这些情况下,可以在剩下的列上创建非聚集索引。如果新索引符合和现有索引符合覆盖索引的要求,优化器将能够使用索引交叉。在为新确定列及其顺序时,也要注意其他查询,以尝试使其最大化。

  索引交叉和索引连接有什么区别呢?前面说到果,索引连接是索引交叉的特例。索引连接在交叉了之后,不用再转到基本表,少了一步书签查找。而索引交叉之后,还有一步书签查找转到基本表获得数据,因为索引交叉的返回列并不能完全符合SELECT的列。

  这是一个聚集表扫描,并没有有效地使用索引。

  当我们建立非聚集索引,且加上过滤后:INCLUDE()是为了形成覆盖索引。

  CREATE NONCLUSTERED INDEX INDEX_Name ON Person(Name) INCLUDE(Age) WHERE Name IS NOT NULL  --过滤的索引上过滤掉NULL值的行

  技术分享

   在我的数据库当中,建立索引,加不加过滤没太大区别(因为很遗憾,Name列基本上没有NULL的),但是当过滤条件IS NOT NULL能够过滤很多条数据的时候,这时过滤的作用才能够展示出来如果过滤条件,能够筛选掉很多条数据,那么性能无疑会大有提升。

  过滤索引再许多方面带来回报:

  •   减少索引尺寸从而增进查询效率;
  •   建立更小的索引降低存储开销;
  •   因为尺寸减小,降低了索引维护的成本;

 

热门排行

今日推荐

热门手游