3.2 “缺失”的索引
3.2.1 索引查找与索引扫描
(1)对于堆数据表
如果数据表是一个堆结构,在使用 SELECT 语句访问堆表时,查询执行计划只有一个表扫描(Table Scan)。表扫描意味着必须扫描整张表,表的数据量越多,查询开销越大。
如果在堆上创建合适的非聚集索引,可以有效地降低查询开销。查询执行计划可以通过索引查找(Index Seek)在叶级找到一个指向数据行的指针,然后通过这个指针在堆上迅速找到数据行。
(2)对于聚集索引表
如果数据表是一个聚集索引结构,在使用 SELECT 语句查询时,查询执行计划可以是聚集索引扫描(Clustered Index Scan)或聚集索引查找(Clustered Index Seek)。
对于聚集索引上的非聚集索引,则可能产生一个书签查找(Bookmark Lookup)。首先在非聚集索引上执行索引查找,在叶级找到一个指向聚集索引的指针,然后再去通过指针在聚集索引中搜索键值(Key Lookup),最终找到记录的其他列值。
3.2.2 “缺失”的索引
提交一个查询时,查询优化器就分析和优化这个查询,然后选择满足查询的最高效方法,为查询创建一个优化的执行计划。即使要查询的表没有索引,查询优化器仍然会对表中的每一列进行基本的分布统计。
因此,在缺少索引的情况下,查询优化器仍然可以确定索引的存在是否有利于查询。如果已经启用了AUTO_CREATE_STATISTICS选项,查询优化器会在确定创建索引可提高效率后,自动生成统计信息,随后的查询就可以用它来提高性能。
查询优化器确定索引能提高性能,但索引却不存在,这时候查询优化器会创建一个“索引缺失”的状态。从sys.dm_db_missing_index_details视图可以看到某个可能需要建立的索引“缺失”的次数。
索引缺失DMV会列出某些列的多种排列组合,为创建索引提供建议。列的每一个组合都会产生一个索引缺失,并生成一个条目。用于计算“有效因素”的查询语句如下:
SELECT * FROM (SELECT user_seeks * avg_total_user_cost * (avg_user_impact * 0.01) AS index_advantage, migs.* FROM sys.dm_db_missing_index_group_stats migs) AS migs_adv INNER JOIN sys.dm_db_missing_index_groups AS mig ON migs_adv.group_handle = mig.index_group_handle INNER JOIN sys.dm_db_missing_index_details AS mid ON mig.index_handle = mid.index_handle ORDER BY migs_adv.index_advantage |
3.2.3 查看索引使用情况
尽管替换了 DBCC SHOWCONTIG 的 sys.dm_db_index_physical_stats 功能强大,并有助于显示索引是否健全,但您还会经常遇到更为复杂的问题,如确定哪些索引可用于针对表而执行的查询。通常,数据库开发人员或管理员会针对他们认为在查询执行期间查询优化器会用到的表来生成索引。
SQL Server 的先前版本中,很难知道这些索引是否确实在使用中。用户只有删除相应索引然后查看查询性能是否受到影响,或者是捕获查询的执行计划然后扫描索引的使用情况。现在有了一个新的 DMV(动态管理视图)sys.dm_db_index_usage_stats,这样,您很容易就可以了解到查询优化器使用索引的情况及针对表格执行查询的情况。您可以通过检查此视图来确定索引的有用性,这样您就可以删除查询优化器未在使用的任何索引。您不必再担心索引是否只是在浪费存储空间,或者对无用索引的维护会降低数据库性能。
通过检查此 DMV 的输出结果可得出没有经过搜索和扫描的索引,这样就可确定自上次启动 SQL Server 以来某索引是否曾经使用过。不过,请记住,许多 DMV 和 DMF 不是永久有效,一旦 SQL Server 重启,它们就会将自身重置为零。在使用 DMV 或 DMF 确定索引的使用情况时,请将这一点考虑进去。某索引可能会自上次重新启动服务以来一直没有使用过,但在周末、月末或季度报表查询时却需要该索引。
3.2.4 查看索引操作的活动
如果希望了解索引的操作活动,可以使用动态管理函数(DMF)sys.dm_db_index_operational_stats 来查看数据库中每个索引的 I/O、锁定、闭锁和访问方法活动,它们能够帮助您了解索引的使用情况以及诊断因过多的 I/O 活动或索引中存在“热点”而引起的索引锁定问题。
使用此 DMF 的闭锁等待列可帮助确定 READ 和 WRITE 操作为获取对某索引资源的访问权限而花费的时间量。这可帮助您确定用于存储索引的磁盘子系统是否足以应付索引的 I/O 活动。它还可以指出索引的设计和使用情况是否引发了热点;热点是由于在索引的一个或多个页面中活动频繁从而导致争用这些页面中所包含的数据。这样的争用经常会导致对该区域尝试进行的 READ 或 WRITE 操作的大量阻塞。
sys.dm_db_index_operational_stats 函数有4个参数,与sys.dm_db_index_physical_stats 的参数类似。前面2个参数分别是db ID和table ID,第3个为index ID(null则显示所有的索引),第4个为partition ID(null则显示所有的分区)。
SELECT page_latch_wait_count , page_latch_wait_in_ms , row_lock_wait_in_ms , page_lock_wait_in_ms , row_lock_count , page_lock_count , page_io_latch_wait_count , page_io_latch_wait_in_ms FROM sys.dm_db_index_operational_stats (DB_ID(‘db01‘) , OBJECT_ID(‘table1‘) , NULL , NULL ) |