SQL Server 查询性能优化——覆盖索引(一)中讲了覆盖索引的一些理论。

  本文将具体讲一下使用不同索引对查询性能的影响。
  下面通过实例,来查看不同的索引结构,如聚集索引、非聚集索引、组合索引等来查看相同的SQL语句查询的不同性能
 
例一:没有任何索引的查询访问
  1.表的碎片情况:
 
  2.SQL查询语句与查询执行计划成本
 
--要求返回IO统计,也就是数据页访问的数量
SET STATISTICS IO ON
--没有任何索引情况下的数据页访问数量
SELECT  [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]

FROM [WBK_PDE_LIST_ORG_HISTROY] where qty_1 between 50 and 500

--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取1568 次,物理读取54 次,预读1568 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读 0 次。
SET STATISTICS IO OFF
 
 
例二:通过聚集索引查询访问
  1.聚集索引的碎片情况:
 
  2.SQL查询语句与查询执行计划成本  
 
--要求返回IO统计,也就是数据分页访问的数量
SET STATISTICS IO ON
---通过聚集索引查询访问的数据页数量
create clustered index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY](QTY_1)
SELECT [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]
  FROM [WBK_PDE_LIST_ORG_HISTROY] where qty_1 between 50 and 500
--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取351 次,物理读取4 次,预读345 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
 
SET STATISTICS IO OFF
---
drop index [WBK_PDE_LIST_ORG_HISTROY].idx_WBK_PDE_LIST_ORG_HISTROY
---
 
 
例三:强制通过非聚集索引查询访问
  1.非聚集索引的碎片情况:
 
  2.SQL查询语句与查询执行计划成本
 
--要求返回IO统计,也就是数据页访问的数目
SET STATISTICS IO ON
--强制通过非聚集索引查询访问的数据页数量,用错索引比不用索引更糟糕
create  index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY](WBOOK_NO)
SELECT [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]

FROM [WBK_PDE_LIST_ORG_HISTROY] with (index(idx_WBK_PDE_LIST_ORG_HISTROY)) where qty_1 between 50 and 500

--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取61065 次,物理读取864 次,预读727 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
SET STATISTICS IO OFF
---
drop index [WBK_PDE_LIST_ORG_HISTROY].idx_WBK_PDE_LIST_ORG_HISTROY
 
 
例四:通过字段顺序不适用的覆盖索引查询访问
  1.非聚集索引的碎片情况:
 
  2.SQL查询语句与查询执行计划成本
 
--要求返回IO统计,也就是数据页访问的数量
SET STATISTICS IO ON
--通过字段顺序不适用的覆盖索引查询访问的数据页数量
create  index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY]([WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT])
SELECT [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]

FROM [WBK_PDE_LIST_ORG_HISTROY] where qty_1 between 50 and 500

--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取687 次,物理读取9 次,预读683 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
SET STATISTICS IO OFF
---
drop index [WBK_PDE_LIST_ORG_HISTROY].idx_WBK_PDE_LIST_ORG_HISTROY
 
 
例五:通过覆盖索引查询访问
  1.非聚集索引的碎片情况:
 
  2.SQL查询语句与查询执行计划成本
 
--要求返回IO统计,也就是数据页访问的数量
SET STATISTICS IO ON
--通过覆盖索引查询访问的数据页数量
create  index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY]([QTY_1]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[WBOOK_NO]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT])
SELECT  [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]

FROM [WBK_PDE_LIST_ORG_HISTROY] where qty_1 between 50 and 500

--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取178 次,物理读取5 次,预读175 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
SET STATISTICS IO OFF
---
drop index [WBK_PDE_LIST_ORG_HISTROY].idx_WBK_PDE_LIST_ORG_HISTROY
 
 
例六:通过字段顺序不适用的覆盖索引查询访问
  1.聚集索引的碎片情况:
 
  2.SQL查询语句与查询执行计划成本
 
--要求返回IO统计,也就数据页访问的数量
SET STATISTICS IO ON
---通过字段顺序不适用的覆盖索引查询访问的数据页数量
create  index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY]([WBOOK_NO]) include(qty_1
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT])
SELECT  [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]

FROM [WBK_PDE_LIST_ORG_HISTROY] where qty_1 between 50 and 500

--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取682 次,物理读取1 次,预读492 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
SET STATISTICS IO OFF
---
drop index [WBK_PDE_LIST_ORG_HISTROY].idx_WBK_PDE_LIST_ORG_HISTROY
 
 
例七:通过子叶层覆盖索引查询访问(INCLUDE)
 
  1.聚集索引的碎片情况:
  2.SQL查询语句与查询执行计划成本
 
--要求返回IO统计,也就是数据页访问的数量
SET STATISTICS IO ON
--通过子叶层覆盖索引查询访问的数据页数量

create  index idx_WBK_PDE_LIST_ORG_HISTROY on [WBK_PDE_LIST_ORG_HISTROY](qty_1) include([WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT])

SELECT  [WBOOK_NO]
  ,[COP_G_NO]
  ,[G_NO]
  ,[CODE_T]
  ,[QTY_1]
  ,[UNIT_1]
  ,[TRADE_TOTAL] 
  ,[GROSS_WT]

FROM [WBK_PDE_LIST_ORG_HISTROY] where qty_1 between 50 and 500

--表'WBK_PDE_LIST_ORG_HISTROY'。扫描计数1,逻辑读取177 次,物理读取4 次,预读173 次,lob 逻辑读取0 次,lob 物理读取0 次,lob 预读0 次。
SET STATISTICS IO OFF
drop index [WBK_PDE_LIST_ORG_HISTROY].idx_WBK_PDE_LIST_ORG_HISTROY
 
 
访问方式分页
逻辑读
物理读
预读
估计运算符开销
全表扫描
1568
54
1568
1.06575
以QTY_1字段建立聚集索引
351
4
345
0.275863
以WBOOK_NO字段建非立聚集索引
61065
864
727
14.10295
以[WBOOK_NO],[COP_G_NO],[G_NO],[CODE_T],[QTY_1],[UNIT_1],[TRADE_TOTAL] ,[GROSS_WT]八个字段建复合索引
687
9
683
0.570198
以[QTY_1],[COP_G_NO],[G_NO],[CODE_T],[WBOOK_NO],[UNIT_1],[TRADE_TOTAL],[GROSS_WT]八个字段建复合索引
178
5
175
0.146974
以WBOOK_NO建立索引,include以下字段 [QTY_1],[COP_G_NO],[G_NO],[CODE_T],[UNIT_1],[TRADE_TOTAL],[GROSS_WT]
682
1
492
0.570198
以[QTY_1]建立索引,include 以下字段[WBOOK_NO],[COP_G_NO],[G_NO],[CODE_T],[UNIT_1],[TRADE_TOTAL],[GROSS_WT]
177
4
173
0.146974
 例一/例二/例三/例四/例五/例六/例七
8.8/2/345/3.9/1/3.9/1
54/4/864/9/5/1/4
8.8/2/4.1/3.9/1/2.8
7.2/1.9/96/3.9/1/3.9/1
 
从上表中可以得出一个结论,如果索引使用不当,例如上面的例三——强制使用选择性很低的索引来查找数据(或是索引统计数据错误、优化引擎误判等,造成索引使用不当),反而会导致大量的I/O操作(逻辑读61065次,物理读864次),其成本比进行全表扫描(例一)还高。
 
例二,通过聚集索引来查找,因为缩小了数据表扫描范围,所以效果较佳。
例五、例七,建立覆盖索引,因为数据结构远小于数据表本身,所以不管组合索引的字段顺序是否正确,都有更好的查询效果。当然 ,依WHERE条
件所需要的字段建立索引数据摆放顺序,也就是[QTY_1]放在索引顺序的第一位,再include查询所需要的字段([WBOOK_NO],
[COP_G_NO],[G_NO],[CODE_T],[UNIT_1],[TRADE_TOTAL],[GROSS_WT]),其查询性能最佳。
 
最后要提醒注意:
1) 在建立覆盖查询时要尽量限制索引键值的大小,保持Row-to-key的大小比例差异越大越好。否则扫描覆盖索引与扫描数据表所花的I/O操作差不多,这样就失去了建立覆盖索引的意义。
2) 覆盖索引可以用来提升查询性能,因为索引中包含了所有查询里的列.非聚集索引为表里的每一行用索引键值来存储一行。另外SQL Server能使用索引页级里的这些行来执行聚集计算。这意味着SQLServer不必去实际的表执行聚集计算,这样可以提升性能。
 
3) 覆盖索引能提升获取数据的性能,但它们也能降低INSERT、UPDATE和DELETE操作的性能。这是因为维护覆盖索引要求做一些额外的工作。通常这不是问题,除非你的数据库经常进行非常高的INSERT、UPDATE和DELETE操作。你也许不得不在你的产品系统上应用覆盖索引之前,要先进行实验,看看你所建立的覆盖索引是否在提升性能方面上比影响性能方面更有帮助。
4) 应该在那些SELECT查询中常使用到的列上创建覆盖索引,但覆盖索引中包括过多的列也不行,因为覆盖索引列的值是存储在内存中的,这样会消耗过多内存,引发性能下降。
 
关于索引碎片的修复:
 
关于上图的一些说明:
avg_fragmentation_in_percent:逻辑碎片(索引中的无序页)的百分比。这是索引的叶级页中出错页所占的百分比。对于出错页,分配给索引的下一个物理页不是由当前叶级页中的“下一页”指针所指向的页。 
fragment_count : 索引中的碎片(物理上连续的叶页)数量。 
avg_fragment_size_in_pages :索引中一个碎片的平均页数。 
知道索引碎片程度后,可以使用下表确定修复碎片的最佳方法。
 
avg_fragmentation_in_percent 值
修复语句
> 5% 且 < = 30%
ALTER INDEX REORGANIZE
> 30%
ALTER INDEX REBUILD WITH (ONLINE = ON)

SQL Server查询性能优化——覆盖索引(二)的更多相关文章

  1. SQL Server 查询性能优化——覆盖索引

    覆盖索引又可以称为索引覆盖. 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖. 解释二: 索引是高效找到行的一个方法,当能通过检索索引 ...

  2. SQL Server查询性能优化——覆盖索引(一)

    覆盖索引又可以称为索引覆盖. 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖. 解释二: 索引是高效找到行的一个方法,当能通过检索索引 ...

  3. SQL Server查询性能优化——创建索引原则(一)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页 就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索 ...

  4. SQL Server 查询性能优化——创建索引原则(一)(转载)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...

  5. SQL Server 查询性能优化——创建索引原则(一)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...

  6. SQL Server 查询性能优化——创建索引原则

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...

  7. SQL Server 查询性能优化——创建索引原则(二)

    三:索引的建立原则 一般来说,建立索引要看数据使用的场景,换句话来说哪些访问数据的SQL语句是常用的,而这些语句是否因为缺少索引(也有可能是索引过多)变的效率低下.但绝不是所有的SQL语句都要建立索引 ...

  8. SQL SERVER 查询性能优化——分析事务与锁(五)

    SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...

  9. SQL Server 查询性能优化 相关文章

    来自: SQL Server 查询性能优化——堆表.碎片与索引(一) SQL Server 查询性能优化——堆表.碎片与索引(二) SQL Server 查询性能优化——覆盖索引(一) SQL Ser ...

随机推荐

  1. Linux时间设置

    Linux时间分为系统时间和硬件时间. 查看系统时间:date 将系统时间写入硬件:hwclock --systohc 查看硬件时间:hwclock --show 将硬件时间写入系统:hwclock ...

  2. 一个页面,多个flash(刚学jq插件)

    只贴js那部分哦 调用 // flash轮播图 var sumF=$('.btnTabs span').length/4; //有四个flash var flashT01=new flash($('. ...

  3. 摘自淘宝的js地区组件

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 利用数据库链做DML操作时报ORA-02069: global_names parameter must be set to TRUE for this operation

    按照 http://space.itpub.net/195110/viewspace-711110 的说法顺利解决问题. 通过DBLink更新远程数据的时候,如果使用到本地的sequence.函数.过 ...

  5. awk的使用备忘

    [转]http://www.cnblogs.com/mydomain/archive/2012/09/24/2699467.html awk引用外部变量   一.用awk 有以下几种方法去调用变量: ...

  6. 【JPA】表达条件查询的关键字

    1.通过解析方法名创建查询 框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find.findBy.read.readBy.get.getBy,然后对剩下部分进行解析.并且如果方法的最后一 ...

  7. 开发设计模式(一)Command模式

    Command定义 将来自客户端的请求传入一个对象,无需了解这个请求激活的 动作或有关接受这个请求的处理细节. 这是一种两台机器之间通讯联系性质的模式,类似传统过程语 言的 CallBack功能. 优 ...

  8. 刷漆(Codechef October Challenge 2014:Remy paints the fence)

    [问题描述] Czy做完了所有的回答出了所有的询问,结果是,他因为脑力消耗过大而变得更虚了:).帮助Czy恢复身材的艰巨任务落到了你的肩上. 正巧,你的花园里有一个由N块排成一条直线的木板组成的栅栏, ...

  9. Linux开启服务器问题(李蕾问题)

    每次启动192.168.1.223服务器时,都要执行这个命令! #:service iptables stop

  10. python与编码

    Python中的文字对象 Python 3.x中处理文字的对象有str, bytes, bytearray. bytes和bytearray可以使用除了用作格式化的方法(format, format_ ...