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

一,统计索引的使用次数

在用户成功提交查询语句时,执行计划中每一个单独的索引操作(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 计数器,这说明基础表会执行大量的更新操作,维护索引更新的开销比较大,数据库引擎利用索引提升查询性能的空间有限。

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

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

  • 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。

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

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

二,统计索引的物理存储

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

  • avg_fragmentation_in_percent:索引外部碎片的百分比,值越大,说明索引的逻辑顺序和物理顺序差异越大,查找性能越低;
  • fragment_count:分段的数量,表示索引数据的集中/分散程度;
  • avg_fragment_size_in_pages:分段的大小
  • avg_page_space_used_in_percent:索引内部碎片的百分比,值越大,说明page空间的利用率越高;

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

三,底层操作的计数

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

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

  • 幽灵数据(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数据页,这个过程是数据列的拉回。

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的争用:

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

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

  • 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。

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

  • 如果发现字段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 可以检测查询优化器建议创建的缺失索引。

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

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

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

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

在实际的数据库系统中,缺失索引可能很多,但是,并不是所有的缺失索引都对查询性能的提升有同等重要的作用,这可以通过系统视图: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

重要的字段注释:

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

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

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

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

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

参考文档:

An in-depth look at Ghost Records in SQL Server

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

Lookup component 用法的更多相关文章

  1. OleDb Source component 用法

    OleDb Source component 主要是从DB中获取数据,传递给下游组件,OleDb Source component的强大之处在于 query data 的mode有四种,如图 Tabl ...

  2. Script component 用法

    在SSIS中,可以使用C#编写脚本,这是十分激动人心的事,能够使用C#代码,使得Script Component无所不能. 第一部分:组件简介Script Component 有三种类型:Source ...

  3. Excle中LOOKUP经典用法

    在Excle中我们经常会遇到需要求根据某个区间的判断然后获取到对应的结果,下面是一个具体的实现例子: 例如: 现在需要实现,当输入0到25以内的任何数字时,会自动获取相应的英文字母 =IFERROR( ...

  4. Conditional Split component 用法

    Conditional Split 用于将数据流按照条件进行拆分,每一个output 都有name和condition. 数据流逐行按照condition进行match,如果match,那么改行会进入 ...

  5. vue 组件 Vue.component 用法

    todo https://blog.csdn.net/weixin_41796631/article/details/82929139

  6. Lookup 组件用法全解

    Lookup是查找的意思,Lookup组件实现两个数据源的连接,和Join语句实现的功能类似,使用Lookup 组件需要配置: 两个输入:一个是上游数据流的输入Source Table,一个是要查找的 ...

  7. Derived Column 用法

    Derived Column Component 用法是为数据流增加派生列,Derived column  有两种用法:add as new column 或 replace . 图中,增加一个 De ...

  8. informatica powercenter学习笔记(LookUp 使用)

    LOOKUP TRANSFORMATION的使用点评: LOOKUP基本用法不熟的话请参考下附属信息. 用法感受: 1 LOOKUP的作用跟我们以前在EXCEL的函数功能类似,就是隔表取值.优点就是用 ...

  9. 一篇文章看懂angularjs component组件

     壹 ❀ 引 我在 angularjs 一篇文章看懂自定义指令directive 一文中详细介绍了directive基本用法与完整属性介绍.directive是个很神奇的存在,你可以不设置templa ...

随机推荐

  1. 【转载】Java集合类Array、List、Map区别和联系

    Java集合类主要分为以下三类: 第一类:Array.Arrays第二类:Collection :List.Set第三类:Map :HashMap.HashTable 一.Array , Arrays ...

  2. Codeforces Round #345 (Div. 1) A. Watchmen

    A. Watchmen time limit per test 3 seconds memory limit per test 256 megabytes input standard input o ...

  3. 爬虫研究-主要针对ali

    公司一个同事想爬取ali的网页受挫,自己跟着尝试了下,发现存在anti-spdier.准备了解下反爬虫,看怎么处理ali. http://www.freebuf.com/news/topnews/96 ...

  4. compass typography 排版 常用排版方法[Sass和compass学习笔记]

    Bullets 用来定义ul li 相关的样式 no-bullet  关闭 li的默认样式 那个小圆点 no-bullets 作用域ul 调用no-bullet 函数 不过用了reset 后 默认没有 ...

  5. windows下面安装Python和pip终极教程

    在大二的时候接触过一段时间的Python,最近又开始玩起了这门语言.总的来说,个 人很喜欢Python的语言风格,但是这门语言对于windows并不算很友好,因为如果是初学者在windows环境下安装 ...

  6. css 大话盒子模型

    什么是盒子模型? CSS中, Box Model叫盒子模型(或框模型),Box Model规定了元素框处理元素内容(element content).内边距(padding).边框(border) 和 ...

  7. cocoapods安装及使用

    最近新换了电脑,重新安装cocoapods遇到了很多问题,在这里把问题还有解决方案记录一下 一.安装Cocoapods 在安装CocoaPods之前,首先要在本地安装好Ruby环境,一般Mac下都自带 ...

  8. JAVA自定义注解

    在学习使用Spring和MyBatis框架的时候,使用了很多的注解来标注Bean或者数据访问层参数,那么JAVA的注解到底是个东西,作用是什么,又怎样自定义注解呢?这篇文章,即将作出简单易懂的解释. ...

  9. 谈BFC和haslayout

    今天提到BFC和haslayout,就顺带在网上查查资料,总结一下它们. CSS2我们再熟悉不过,当然它里面我们需要掌握的,就是CSS2的选择器和布局,选择器总共31种.避开这个不说,我们说布局. 布 ...

  10. GIT 版本控制常用命令学习汇总

    GIT 版本控制常用命令汇总 git version 查看当前git版本信息 git help 获取全部命令帮助信息 git help <command> 获取指定命令帮助信息 git c ...