另外一个影响查询性能的因素跟DML查询已经删除,插入以及更改数据的查询有关。在指定表上创建的索引越多,更改数据时需要占用的资源也就越多。当事务之间存在锁的组合时,较长的更改操作会破坏并发性。结果,所以,了解哪个索引被应用程序超时使用就显得很重要。然后你就可以指出是否在数据库中结构中存在着从未被使用过的索引。
SQL Server2008提供了sys.dm_db_usage_stats DMV,它显示出了哪些索引被使用以及它们是在被用户查询所使用还是仅仅共系统操作使用。伴随着查询的每一次执行,这个动态管理试图返回的列会随着查询语句中使用的执行计划的增加而增加。数据是在SQL Server运行的时候被收集的。这个dmv中数据仅被存储在内存中,并且不会被永久保存。所以当SQL Server实例停掉以后,数据也会丢失。你可以间歇性地获取并保存这些信息,便于以后对它们进行分析。
在索引上的操作被划分为用户类型及系统类型两种。用户类型倾向于SELECT,INSERT,DELETE以及UPDATE操作,或者更新统计信息。两种类别的语句在列中对比显示如下:
对于这些在索引上的每一种操作,最后的访问都会被标记上一个时间戳。索引本身通过三个列被识别:database_id,object_id,index_id。index_id=0表示一个堆类型的表,index_id=1表示一个群集索引,index_id>1表示一个非聚集索引。
应用程序在数据库上持续应用,sys.dm_db_index_usage_stats可访问的索引列表也会随之增加。
SQL Server上scan,seek,以及lookup工作的定义及规则如下:
下面的DMV查询可以被用来去获取所有数据库上的所有对象的索引使用信息:
select object_id, index_id, user_seeks, user_scans, user_lookups from sys.dm_db_index_usage_stats order by object_id, index_id
你可以参考下面的输出
object_id index_id user_seeks user_scans user_lookups -------------------------------------------------------------------- 521690298 1 0 251 123 521690298 2 123 0 0
当前情况下有251个对应于某一查询的执行直接访问数据层中的表,而没有使用任意一个索引。有123个对应于某一查询的执行通过第一个非聚集索引访问表,它既没有涵盖Select中的列也没有涵盖where谓词中指定的列,因为我们看到有123个lookup存在于聚集索引之上。
sys.dm_db_index_usage_stats中最有意思的列是用来查看用户类型的列,包括user_seeks和user_scans。系统使用列,比如system_seeks可以被认为是已经存在的索引的结果。如果索引不存在,它就可以不必强制更新统计信息并且也可以不需要被检查一致性。所以,分析工作需要关注那四个列以指出即时查询及用户应用程序对索引的使用情况。
为了获取指定表在SQL Server最后一次启动后一直未被使用的索引的信息,可以在拥有这个对象的数据库中运行下面查询:
from sys.indexes i where i.object_id=object_id('') and i.index_id NOT IN (select s.index_id from sys.dm_db_index_usage_stats s where s.object_id=i.object_id and i.index_id=s.index_id and database_id = <dbid> )
所有未被使用过的索引可以通过下面的语句获取到:
select object_name(object_id), i.name from sys.indexes i where i.index_id NOT IN (select s.index_id from sys.dm_db_index_usage_stats s where s.object_id=i.object_id and i.index_id=s.index_id and database_id = <dbid> ) order by object_name(object_id) asc
当前的情况,表名及索引名称按照表名被存储。
这个DMV的真实目的是观察长时间运行的索引的使用情况。可能最好是去创建一个针对视图的快照或者针对结果的快照并且存储起来,按照这种方式每天执行一次并且去对比彼此的变化。如果你可以明确识别出哪个索引已经好几个月或者有段时间都没有被使用过了,你可以最终从数据库中删除掉这些索引。