必发88手机客户端 7

目录总结,索引碎片的检查评定和整治

存储数据是为了查找数据,存储结构影响数据查找的性能。对无序数据进行查找,最快的查找算法是哈希查找;对有序数据进行查找,最快的查找算法是平衡树查找。在传统的关系型数据库中,聚集索引和非聚集索引都是平衡树(B-Tree)类型的存储结构,用于顺序存储数据,便于实现数据的快速查找。除了提升数据查找的性能之外,索引还能减少硬盘IO和内存消耗。通常情况下,硬盘IO是查找性能的瓶颈,由于索引是数据表的列的子集,这意味着,索引只存储部分列的数据,占用的硬盘空间比全部列少了很多,因此,数据库引擎只需要消耗相对较少的硬盘IO和内存buffer,就能把索引数据加载到内存中。

数据库引擎是高度优化的闭环系统,基于执行计划的反馈,查询优化器在一定程度上自动优化现有的执行计划。查询优化的核心是索引优化,数据库引擎通过计数器统计关于索引操作的数据,统计的信息包括:使用次数、物理存储、底层操作的计数,以及缺失索引等,这些统计数据存储在内存中,是数据库引擎执行情况的真实反馈,高度概括了索引的执行情况,有意识地利用索引的统计信息,有针对性地优化现有的业务逻辑代码,调整查询的执行计划,能够提高数据库的查询性能。

索引以B-Tree结构存储在数据文件中,分为叶子节点和非叶子节点,叶子节点用于存储数据,而非叶子节点(中间节点和根节点)用于存储索引键,节点数据按照索引键排序。理论上,一旦数据集确定下来,索引查找的时间消耗就只跟索引结构的层次有关系,层次越多,查找数据所消耗的时间越多。碎片会影响索引的层次结构,但是,碎片并不总是破坏者,碎片有利于数据的更新。

一,统计索引的使用次数

在数据的物理存储上,索引和数据存储在硬盘上的数据文件中,数据文件以页(Page)为最小单位分割,每一个Page是8KB,物理位置上连续的8个Page叫做一个区(Extent),每一个区是64KB。区是空间分配的基本单位,而页是数据存储的基本单位。

在用户成功提交查询语句时,执行计划中每一个单独的索引操作(Seek,Scan,Lookup或Update)都会被统计到sys.dm_db_index_usage_stats
中,例如,user_updates 计数器统计索引执行Insert,Update或Delete操作的次数,查找计数器(user_seeks,
user_scans,
user_lookups
)统计在索引上执行的seek,scan和lookup操作的次数,如果查找计数器远远小于user_updates 计数器,这说明基础表会执行大量的更新操作,维护索引更新的开销比较大,数据库引擎利用索引提升查询性能的空间有限。 

从物理存储上来看,索引是由一系列的分段(Fragment)构成的,每个分段是由连续的数据页(Page)构成的。理想情况下,数据存储的物理顺序和索引键定义的逻辑顺序保持一致,这有利于数据的范围查询,因为机械硬盘不需要移动磁头就可以获取到所需数据。数据的更新(Insert,Update或Delete)有时会更新索引键,组成索引键的字段的Size增加,以至于原来的Page不能容纳该行数据,导致页拆分,致使数据的物理顺序和逻辑顺序不再匹配,产生索引外部碎片。因此,预留少量的页内碎片能够容纳数据行Size的有限增加,减少页拆分(page
split)发生的次数,提高数据更新的性能。通常情况下,大量的索引碎片总是十分有害的,应该把索引碎片控制在一定百分比以下,微软推荐,30%。

在计数时,每一个单独的seek、scan、lookup或update操作都被计算为对该索引的一次使用,并使该视图中的相应计数器加1。

数据更新和数据查找是此消彼长的关系,在索引页中预留空闲空间会增加索引的Size,然而,额外占用的硬盘空间需要额外的硬盘IO加载到内存中,这不利于数据的查找,然而,当发生数据更新时,预留的空间能够容纳数据行Size的增加,减少页拆分发生的次数,这有利于数据的更新,因此,在频繁更新的数据库系统中,为了减少页拆分的次数,需要人为增加索引的内部碎片:

索引的Seek,Scan,Lookup和Update的含义是:

  • FILLFACTOR = fillfactor
  • PAD_INDEX = { ON | OFF }
  • Seek是Index Seek:通过该索引进行查找的次数
  • Scan是Index Scan:通过该索引执行扫描查找的次数
  • Lookup是Key
    Lookup:通过该索引查找到数据后,再到源数据表进行键值查找的次数,Key
    Lookup是非聚集索引特有的,查询性能低下,应避免这种查找方法;
  • Update是Index Update:由于源表数据更新导致索引页更新的次数

在创建索引时,需要权衡数据更新和数据查找对系统的影响,在实际产品环境中,需要设置合适的填充因子,预留索引内部碎片;及时整理索引碎片,消除索引外部碎片,以使数据库达到最优状态。

Index Seek和Index Scan的区别是:

一,索引碎片

  • Index Seek是从BTree的根节点开始,向子节点查找,直到叶子节点;
  • Index
    Scan
    是在Index的叶子节点上,从左到右,把整个BTree的叶子节点遍历一遍,类似于Table
    Scan。

索引碎片分为内部碎片(Internal Fragmentation)和外部碎片(External
Fragmentation),内部碎片是指索引页内部的碎片,在索引页内部存在没有使用的空间,部分空间被闲置,这意味索引页存在空间的浪费,数据实际占用的空间多于需要的空间,因此,当存储相同的数据集时,如果索引的碎片越多,索引结构占用的硬盘空间越多;在处理数据时,数据库引擎需要读取的索引页越多,加载到内存消耗的缓存页(Buffer)越多。内部碎片会出现在索引结构的叶子节点或中间节点,叶子节点中的碎片会导致数据密度降低,而中间节点中的碎片会导致索引键的密度降低。

如果索引的Seek,Scan,Lookup的计数值较多,那么说明索引被引用的次数多;如果查找计数器数值较小,但是Update数值较多,说明维护Index的开销高于查询带来的性能提升,应该考虑修改索引的结构,或者直接把索引删除。

外部碎片是指存储数据的页或区(Extent)的逻辑顺序和物理顺序不一致,逻辑顺序(Logical
Order)是由索引键定义的,物理顺序(Physical
Order)是在硬盘文件中,用于存储数据的页或区的顺序,也就是索引的叶子节点占用的页或区在硬盘上的物理存储的顺序。如果在逻辑上连续的Page或Extent在物理上也是连续的,那么就不存在外部碎片。最有效的顺序是:逻辑顺序上相邻的数据页,在物理顺序上也相邻。

必发88手机客户端 1必发88手机客户端 2

The most efficient order is where the
logical order of the pages and extents(as defined by the index keys,
following the next-page pointers from the page headers) is the same as
the physical order of the pages and extents with the data files. In
other words, the index leaf-lelvel page that has the row with the next
index key is also the next physical contiguous page int the data
file.

select db_name(us.database_id) as db_name
    ,object_schema_name(us.object_id)+'.'+object_name(us.object_id) as table_name
    ,i.name as index_name
    ,i.type_desc as index_type_desc
    ,us.user_seeks
    ,us.user_scans
    ,us.user_lookups
    ,us.user_updates
from sys.dm_db_index_usage_stats us 
inner join sys.indexes i 
    on us.object_id=i.object_id and us.index_id=i.index_id
where us.database_id=db_id()
    --us.database_id=db_id('database_name')
    --and us.object_id=object_id('schema_name.table_name')
order by us.user_seeks desc

 二,检测索引碎片

View Code

可以通过内置函数:
sys.dm_db_index_physical_stats,查看索引的外部碎片,字段
avg_fragmentation_in_percent
用于表示外部碎片的程度,对于索引,以Page为单位统计碎片;对于堆(Heap),以Extent为单位统计碎片,这是因为Heap结构的页(Page)是没有顺序的。在堆(Heap)的
Page Header中,字段 next_page 和 Pre_page
pointer是null。字段 avg_page_space_used_in_percent
用于表示内部碎片的程度,百分比越高,说明单个Page的空间利用率越高。

二,统计索引的物理存储

1,扫描模式

使用 sys.dm_db_index_physical_stats
函数统计索引的物理存储,例如,碎片的百分比,数据存储的集中和分散程度,以及page空间的利用率等:

检测索引的碎片,需要对索引进行扫描,参数mode指定为了获取碎片数据,数据库引擎必须执行的扫描模式,共有三种模式:LIMITED,
SAMPLED, or DETAILED,默认值是LIMITED。

  • avg_fragmentation_in_percent:索引外部碎片的百分比,值越大,说明索引的逻辑顺序和物理顺序差异越大,查找性能越低;
  • fragment_count:分段的数量,表示索引数据的集中/分散程度;
  • avg_fragment_size_in_pages:分段的大小
  • avg_page_space_used_in_percent:索引内部碎片的百分比,值越大,说明page空间的利用率越高;
  • Limited
    模式是最快的,只扫描最小数据量的Page,Limited模式不会扫描数据页(Data
    Page),对于索引,扫描叶子节点的直接父节点;对于Heap,扫描堆表对应的IAM
    和 PFS系统页。
  • 在Sampled模式下,数据库引擎从索引或堆表中抽取1%的Page作为样本数据,根据样本数据来估计碎片的程度。
  • Detailed 模式扫描所有的数据页,耗时最久,返回的信息最详细。

请阅读《索引碎片的检测和整理》,以了解更多。

2,分段和碎片

三,底层操作的计数

分段(Fragment),也叫片段,是指在硬盘文件中,数据的物理存储的集中/分散程度。一个片段是由在物理位置上连续的索引页组成的,Fragment的Size
越大,说明页的物理位置越集中,读取相同数量的Page所需的IO越少,范围读取性能越好。

使用 sys.dm_db_index_operational_stats必发88手机客户端,
函数统计底层IO、加锁(Locking)、Latch和数据访问模式的计数,通过这些数据,用户能够追踪到查询请求必须等待多长时间才能完成数据的读写、标识索引是否存在IO热点。

碎片(Fragmentation)用于描述数据更新对索引结构产生的副作用。页内碎片是指Page
内部存在空闲空间,外部碎片是指Page 或 extent
的物理顺序和所以键定义的逻辑顺序不一致。

在统计索引的底层操作之前,先了解跟数据的物理存储相关的术语:

  • avg_fragmentation_in_percent:碎片百分比,合理的比例是在10左右,比例越大,索引碎片越多,读取性能越差;
  • fragment_count:分段的数量,理论上,分段(Fragment)数量越少越好,间接说明索引的物理顺序和逻辑顺序越匹配;
  • avg_fragment_size_in_pages:每个分段平均包含的Page数量,Fragment的Size
    越大,读取相同数量的Pages所需的IO越少,读取性能越好;
  • avg_page_space_used_in_percent:Page空间的平均利用率,值越大,页内碎片越小;
  • 幽灵数据(ghost)是指:在索引的叶子节点中,数据行被标记为删除,但是还没有从索引结构中物理删除,幽灵数据只存在于索引的叶子节点中,幽灵数据由后台进程定期执行物理删除。
  • 转发数据(forwarding):需要两次IO操作才能获取到指定的数据,转发操作只发生于堆表(Heap)中;当数据行被更新,导致行的Size增大,以致于该行无法存储在当前的page中,为了避免相关索引的更新,数据库引擎会把该数据行转存到一个新的Page中,并在新旧
    Page中分别添加一个Pointer:在原Page中,Pointer指向新Page,该Pointer称作Forwarder
    Pointer;在新page中,Pointer指向原Page,称作Back
    Pointer。在读取数据时,数据库引擎首先从Forwarder
    Pointer中读取数据存储的指针,然后,根据指针到相应的地址空间中读取真正的数据。
  • 获取(Fetch)数据:用于从LOB或Row_Overflow的分配单元(Allocation
    Unit)中取回(Retrive)数据,大字段数据存储在特定的LOB或Row_Overflow类型的数据页中。
  • 剥离(Push
    Off)数据列:用于统计数据库引擎把LOB或Row-Overflow数据从原有的In-Row
    数据页剥离的次数。在执行Insert或Update操作之后,数据行的Size增长,不能存储在当前的Page中,必须把大数据字段的数据从原来的数据行中分离,存储在指定的分配单元中,这个过程就是数据列的剥离。
  • 拉回(Pull In)数据行:是Push
    Off的逆过程,用于统计数据库引擎把数据从LOB或Row-Overflow数据页拉入到In-Row数据页的次数,拉入数据行一般发生在更新数据之后,数据行的Size减小,数据行在释放存储空间之后,能够存储在In-Row
    Page中,数据引擎把数据从LOB或Row-Overflow数据页拉入到In-Row数据页,这个过程是数据列的拉回。

3,检测碎片的脚本

This (pulled in-row) occurs when an
update operation frees up space in a record and provides an
opportunity to pull in one or more off-row values from the LOB_DATA
or ROW_OVERFLOW_DATA allocation units to the IN_ROW_DATA
allocation unit.

通过执行函数,检测索引的碎片:

以下脚本用于统计索引底层的存储动作和锁/Latch的争用:

必发88手机客户端 3必发88手机客户端 4

必发88手机客户端 5必发88手机客户端 6

select ps.database_id,
    ps.object_id,
    ps.index_id,
    ps.partition_number,
    ps.index_type_desc,
    ps.alloc_unit_type_desc,
    ps.index_depth,
    ps.index_level,
    ps.avg_fragmentation_in_percent,
    ps.fragment_count,
    ps.avg_fragment_size_in_pages,
    ps.page_count,
    ps.avg_page_space_used_in_percent,
    ps.record_count,
    ps.ghost_record_count,
    ps.version_ghost_record_count,
    ps.min_record_size_in_bytes,
    ps.max_record_size_in_bytes,
    ps.avg_record_size_in_bytes,
    ps.forwarded_record_count,
    ps.compressed_page_count
from sys.dm_db_index_physical_stats(database_id,object_id,index_id,partition_number,'detailed') as ps
order by ps.index_level
select db_name(ops.database_id) as db_name
    ,object_schema_name(ops.object_id)+'.'+object_name(ops.object_id) as table_name
    ,i.name as index_name
    ,ops.partition_number
    ,ops.leaf_insert_count
    ,ops.leaf_delete_count
    ,ops.leaf_update_count
    ,ops.leaf_ghost_count
    ,ops.nonleaf_insert_count
    ,ops.nonleaf_delete_count
    ,ops.nonleaf_update_count
    ,ops.range_scan_count
    ,ops.singleton_lookup_count
    ,ops.forwarded_fetch_count

    ,iif(ops.row_lock_wait_count=0,0,ops.row_lock_wait_in_ms/ops.row_lock_wait_count) as avg_row_lock_wait_ms
    ,iif(ops.page_lock_wait_count=0,0,ops.page_lock_wait_in_ms/ops.page_lock_wait_count) as avg_page_lock_wait_ms
    ,iif(ops.page_latch_wait_count=0,0,ops.page_latch_wait_in_ms/ops.page_latch_wait_count) as avg_page_latch_wait_ms
    ,iif(ops.page_io_latch_wait_count=0,0,ops.page_io_latch_wait_in_ms/ops.page_io_latch_wait_count) as avg_page_io_latch_wait_ms
from sys.dm_db_index_operational_stats(db_id(),object_id('dbo.FactThread'),null,null) as ops
inner join sys.indexes i 
    on ops.object_id=i.object_id
        and ops.index_id=i.index_id
order by index_name

View Code

View Code

必发88手机客户端 7

该函数统计的Latch征用数据主要分为PageLatch和PageIOLatch,其区别是:

字段avg_fragmentation_in_percent
表示索引碎片的密度,可以接受的百分比是从0到10%,根据碎片的百分比,选择重新组织索引或重新创建索引,以整理碎片。

  • PageLatch是指:在访问数据有关的数据页(Data Page或Index
    Page)时,如果相应的Page已经存在于Buffer Pool中,那么SQL
    Server先获取buffer的latch,这个Latch就是
    PageLatch,然后读取Buffer中的数据。

    PageLatch是施加在Buffer上的Latch, 用来保护:Data page,Index Page,
    系统page(PFS,GAM,SGAM,IAM等)的争用访问;在数据更新时,分配新的page,或拆分
    索引页(Index Page),会产生PageLatch 等待。

  • PageIOLatch是指:用于把数据从索引或Heap中加载到内存。当数据页从物理文件中的Page中读取到内存时,申请对内存Buffer施加的Latch是PageIOLatch。当数据页不在内存里时,SQL
    Server
    先在内存中预留一个Page,然后从硬盘读取,加载到内存Buffer中,此时,SQL
    Server申请并获取的latch类型是PAGEIOLATCH,PageIOLatch表示正在进行IO操作。PageIOLatch_EX表示正在将disk中的数据页加载到内存,PageIOLatch_SH表示在加载数据页到内存期间,试图读取内存中的数据页,此时加载数据页的过程没有完成,处于Loading状态。如果经常出现PageIOLatch_SH,表明Loading数据页的时间太长,可能出现IO
    bottleneck。

返回的字段分析:

分析查询结果,根据计数器的数值,调整数据库,使系统达到最优状态:

  • Index_level=0,表示是索引结构的深度,0表示叶子级别;
  • avg_fragmentation_in_percent:碎片的百分比,表示物理顺序不连续的pages所占的百分比;如果基础表是BTree,
    碎片的计量单位是Page,avg_fragmentation_in_percent和page_count
    的乘积就是物理顺序和逻辑顺序不一致的pages的总数量。
  • fragment_count:片段的数量
  • page_count:page 的数量
  • avg_fragment_size_in_pages:每个Index
    片段平均使用的Pages,是Page_Count和Fragment_Count的比值。
  • avg_page_space_used_in_percent:每个Page内空间的平均使用程度
  • 如果发现字段leaf_ghost_count的数值特别大,说明索引中存储很多幽灵数据,可以通过重建索引(Rebuild)清理幽灵数据行:

    alter index index_name
    on table_name
    rebuild

  • 如果PageIOLatch等待较多,说明数据库频繁的执行硬盘IO操作,可能的原因是内存不足,或者数据文件没有分散到多个物理硬盘上

  • 如果PageLatch等待较多,说明数据库存在IO热点,可以通过增加数据文件ndf,把数据库分散到不同的物理硬盘上,以减少IO热点

三,碎片整理

四,缺失索引

碎片整理有两种方式:重新组织索引和重新创建索引,重建索引是指在一个事务中,删除旧的索引,并重建新的索引,这种方式会回收原有索引的硬盘空间,并分配新的存储空间,以创建索引结构。重组索引是指不分配新的存储空间,在原有的空间基础上,重新组织索引结构的叶子节点,使数据页的逻辑顺序和物理顺序保持一致,并释放索引中多余的空间,这就是说,重组索引是为了减少叶子节点的外部碎片。

查询优化器(Query
Optimizer)在执行查询时,如果检测到执行计划缺失索引,会把缺失索引的相关信息存储在缓存中,通过  sys.dm_db_missing_index_details 可以检测查询优化器建议创建的缺失索引。

使用函数 sys.dm_db_index_physical_stats
检测碎片的程度,字段 avg_fragmentation_in_percent 
 返回的逻辑碎片的百分比,一般情况下,微软推荐以30%为阈值:

该视图返回的缺失索引的索引键及包含列信息,在索引列的顺序上,通常来说,相等列(equality)应该排在不等列(inequality)之前,用户需要根据查询的条件来调整相等列和不等列的顺序,包含列(Included)应该添加到INCLUDE子句中,但是,该视图不会标识出相等列(equality)的排列顺序,需要根据查询语句和选择性来设置,索引键的第一列至关重要。而不等列(inequality)是指除等号(=)之外的比较符号,例如,table.cloumn>value。

  • avg_fragmentation_in_percent >5% and <=30%:
    重组索引(ALTER INDEX REORGANIZE);
  • avg_fragmentation_in_percent >30%: 重建索引(ALTER INDEX
    REBUILD);

必发88手机客户端 8必发88手机客户端 9

以下脚本使用游标(Cusor)逐个整理索引碎片,在重建索引(Rebuild
Index)时,使用的索引选项是:FILLFACTOR = 95, ONLINE = OFF,
DATA_COMPRESSION = PAGE

select mid.index_handle
    ,db_name(mid.database_id) as db_name
    ,mid.object_id
    ,object_name(mid.object_id,mid.database_id) as object_name
    ,mid.equality_columns
    ,mid.inequality_columns
    ,mid.included_columns
    ,mid.statement as underlying_table
    ,mic.column_id
    ,mic.column_name
    ,mic.column_usage    
from sys.dm_db_missing_index_details as mid
cross apply sys.dm_db_missing_index_columns(mid.index_handle) as mic
order by mid.object_id
    ,mid.index_handle

必发88手机客户端 10必发88手机客户端 11

View Code

DECLARE @SchemeName NVARCHAR(MAX)=N'';
DECLARE @TableName NVARCHAR(MAX)=N'';
DECLARE @IndexName NVARCHAR(MAX)=N'';
DECLARE @avg_fragmentation_in_percent FLOAT=0;
DECLARE @SQL NVARCHAR(MAX)=N'';

DECLARE cur_index CURSOR
LOCAL
FORWARD_ONLY
FAST_FORWARD
READ_ONLY
FOR
SELECT
    '['+s.name+']' AS SchemeName,
    '['+o.name+']' AS TableName,
    '['+i.name+']' AS IndexName,
    MAX(ps.avg_fragmentation_in_percent) AS avg_fragmentation_in_percent
FROM sys.indexes i
INNER JOIN sys.objects o
    ON i.object_id = o.object_id
INNER JOIN sys.schemas s
    ON o.schema_id = s.schema_id
INNER JOIN sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, N'DETAILED') AS ps
    ON ps.object_id = i.object_id
    AND ps.index_id = i.index_id
WHERE ps.avg_fragmentation_in_percent >= 10
AND i.type IN (1, 2)    --1: CLUSTERED, 2: NONCLUSTERED
AND o.type = N'U'        --U: USER_TABLE
AND ps.index_level = 0    --Index leaf-level 
GROUP BY    s.name,
            o.name,
            i.name
ORDER BY avg_fragmentation_in_percent DESC;

OPEN cur_index;

FETCH NEXT FROM cur_index
INTO @SchemeName, @TableName, @IndexName, @avg_fragmentation_in_percent;

WHILE(@@FETCH_STATUS=0)
BEGIN
    IF (@avg_fragmentation_in_percent>30)
    BEGIN
        SELECT @SQL = N'ALTER INDEX ' + @IndexName + N' ON ' + @SchemeName + N'.' + @TableName 
                        + N' REBUILD PARTITION=ALL WITH (FILLFACTOR = 95, ONLINE = OFF, DATA_COMPRESSION = PAGE );'
    END 
    ELSE --@avg_fragmentation_in_percent between 10 and 30
    BEGIN
        SELECT @SQL = N'ALTER INDEX ' + @IndexName + N' ON ' + @SchemeName + N'.' + @TableName 
                        + N' REORGANIZE PARTITION=ALL;'
    END

    EXEC (@SQL)

    FETCH NEXT FROM cur_index
    INTO @SchemeName, @TableName, @IndexName, @avg_fragmentation_in_percent;
END

CLOSE cur_index;
DEALLOCATE cur_index;

statement字段是缺失索引的表的名称,object_id字段是缺失索引的表的id,index_handle用于标识缺失的索引。

View Code

缺失的索引都被分组,这意味着每一个缺失索引都被分配到一个特定的分组中,系统根据缺失索引的索引键把缺失索引分配到一个组中。

这个阈值,可以根据产品环境数据更新和查找的实际情况,适度调整。

在实际的数据库系统中,缺失索引可能很多,但是,并不是所有的缺失索引都对查询性能的提升有同等重要的作用,这可以通过系统视图:sys.dm_db_missing_index_group_stats
来度量:

 

select top 111
    g.index_handle
    ,gs.unique_compiles
    ,gs.user_scans
    ,gs.user_seeks
    ,gs.avg_total_user_cost
    ,gs.avg_user_impact
    ,gs.avg_total_user_cost * gs.avg_user_impact * (gs.user_seeks + gs.user_scans) benefit_weight
from sys.dm_db_missing_index_groups g
inner join sys.dm_db_missing_index_group_stats gs
    on g.index_group_handle=gs.group_handle
order by benefit_weight desc

参考文档:

重要的字段注释:

Reorganize and Rebuild
Indexes.aspx)

  • user_scans 和 user_seeks
    是指:如果分组中的索引被创建,用户的查询会引用索引做seek或scan操作的次数。
  • avg_total_user_cost
    是指:如果分组中的索引被创建,用户的查询能够减少的平均开销。
  • avg_user_impact
    是指:如果分组中的索引被创建,用户的查询能够获得的平均收益。

sys.dm_db_index_physical_stats
(Transact-SQL).aspx)

在实际的数据库系统中,数据库管理员需要监控分组的统计数据,根据开销和收益来创建缺失的索引,以最大程序的提高系统查询性能。

五,查看表上创建的所有索引及其定义

通过视图 sys.indexes 和
sys.index_columns 查看在基础表创建的所有索引:

必发88手机客户端 12必发88手机客户端 13

select o.name as table_name
    ,i.index_id
    ,i.name as index_name
    ,i.type_desc as index_type
    ,c.name AS index_column_name
    ,ic.key_ordinal as index_key_ordinal
    ,iif(ic.is_descending_key=1,'desc','asc') as sort_direction
    ,ic.index_column_id
    ,ic.is_included_column
    ,i.fill_factor
    ,i.is_padded
    ,i.has_filter
    ,i.filter_definition
    --,ic.partition_ordinal
from sys.objects o
inner join sys.indexes i
    on o.object_id = i.object_id
inner join sys.index_columns ic
    on i.object_id = ic.object_id 
        and i.index_id = ic.index_id
inner join sys.columns c
    on o.object_id = c.object_id 
        and ic.column_id = c.column_id
where o.name = 'table_name'
    --and i.name='index_name'
order by i.index_id,
    ic.index_column_id

View Code

 

参考文档:

An in-depth look at Ghost Records in SQL
Server

Index Related Dynamic Management Views and Functions
(Transact-SQL).aspx)