当前位置:  数据库>sqlserver

Sql Server 查询性能优化之走出索引的误区分析

    来源: 互联网  发布时间:2014-10-07

    本文导语:  据了解绝大多数开发人员对于索引的理解都是一知半解,局限于大多数日常工作没有机会、也什么没有必要去关心、了解索引,实在哪天某个查询太慢了找到查询条件建个索引就ok,哪天又有个查询慢了,再建立个索引就是,...

据了解绝大多数开发人员对于索引的理解都是一知半解,局限于大多数日常工作没有机会、也什么没有必要去关心、了解索引,实在哪天某个查询太慢了找到查询条件建个索引就ok,哪天又有个查询慢了,再建立个索引就是,或者干脆把整个查询SQL直接发给DBA,让DBA直接帮忙优化了,所以造成的状况就是开发人员对于索引的理解、认识很局限,以下就把我个人对于索引的理解及浅薄认识和大家分享下,希望能解除一些大家的疑惑,一起走出索引的误区

误区1.在表上建立了索引,在查询时用到了索引的列,索引就一定会生效
  首先明确下这样的观点是错误的,SQL Server查询优化器是基于开销进行选择的优化器,通过一系列复杂判断来决定是否使用索引、使用什么类型索引、使用那个索引。SQL Server内部维护着索引列上的数据的统计,统计信息会随着索引列内容的变化而变化,索引的有效期完全取决于索引列上的统计信息,随着数据的变化关于索引的检索机制也随之变化。对于查询优化器来说始终保持查询开销最低始终是其的不二选择,如果一个非聚集索引的列上有大量的重复值,那么这个索引就不会有什么存在的意义,这也是为什么不建议在类似性别,bit类型上面建立非聚集索引的原因。

  说到这里可能会有人疑惑,我在性别列上建一个索引,性别只有两个值男、女,当我我们查询条件中有性别这个字段时最起码会过滤掉一半的数据,能大幅缩小我们需要检索的数据范围,怎么会没用呢?(事实上这也是我曾经困惑的地方),对我们理解的没错,比如说Users表性别列Gender上建立索引IX_Gender,执行select Gender from Users where Gender='男' ,这个查询效率非常高而且也成功使用了索引IX_Gender,然而我们这样写SQL的时候少之又少,更多的我们会写这样的SQL:select UserID,UserName,Phone,Email from Users where Gender='男' 这时再去看看查询计划根本没用使用索引IX_Gender,而是进行了一个聚集索引扫描或者表扫描,查询条件where Gender='男' 明明在IX_Gender里面定义了,为什么没使用呢,这一切罪恶的根源就在于书签查找(RID、键查找),好了关于书签查找不是我们要讨论的话题,在这里只想告诉大家,索引不是万能的,索引不是创建了就一定有效。

误区2.聚集索引扫描用到了聚集索引索引,所以性能很高
  一般来说我们可以认为聚集索引是效率最高的索引,但聚集索引扫描绝不代表高效,本质上聚集索引扫描就是表扫描,一般出现扫描字样时代表缺少索引或者索引无效,所以我们日常应用中应该避免在查询计划中看到扫描字样,更多的出现聚集索引查找、索引查找才真正的使用到了索引,才是王道。

误区3.聚集索引扫描(表扫描)是全表扫描,所以只要出现了表扫描就一定代表性能低下
  在误区2中我们说到应该尽量避免出现聚集索引扫描或者表扫描,这是我们必须要坚持的原则,但这并不代表这出现表扫描就一定性能低下,有些情况下表扫描反而比索引查找有着更高的效率(一般出现在返回数据量较大,出现大量书签查找的情况下)

误区4.查询计划中看到了键查找或者RID查找时有着很高的性能
  键查找和RID查找统称为书签查找,和错误认识正好相反,出现书签查找反而代表着性能低下,有些情况下甚至有着比表扫描更低的效率,因此我们应该尽量避免书签查找。在返回数据量较小时,书签查找对性能影响不大,若返回数据量较大,书签查找会严重影响查询性能,因此我们建立索引时应该尽量覆盖要返回的所有列,当然索引列数是有限的而且也不能单纯的为了避免书签查找而在索引中包含大量的列,可以使用覆盖索引来解决书签查找问题,或者需要大数据量返回时尽量使用聚集索引;同时这也是为什么常听说的不要使用select *,而只选择需要的列进行输出,因为select *很容易导致书签查找,毕竟我们不打可能在所有列上建立索引,也不可能所有查询都使用聚集索引(使用聚集索引和表扫描时不存在书签查找)

误区5.查询开销统计中的逻辑读次数是读取的记录数
  天真的我曾经也这么认为,查询计划中逻辑读次数就是读取的记录数,然而看我们的查询4.1全表扫描返回830行数据,为啥逻辑读只有22次,而查询4.5同样是返回830行数据,逻辑读为啥1724次呢,一次读取一条的话逻辑读22次最多返回22行数据,逻辑读1724次的话应该返回1724条数据吧,有点小晕,这里解释下逻辑读次数是指读取的页面数,一个面8KB,8个页面构成一个区64KB,对于我们的示例表来说22个页面足以存下所有数据,所以表扫描时只需读取22次就可以了,那查询4.5为啥读取了1724次呢,就算一个页面就一条数据按理说最多800多次也可以读取完毕了,这是因为Sql Server对数据读取的最小单位就是页,哪怕读取一条数据也需要读取整页数据,而非聚集索引的读是随机读哪怕多条记录在同一页上也会导致多次重复读取,外加书签查找导致了这么多的逻辑读,这也是为什么非聚集索引不适合读取大量数据的原因之一。


我们以Northwind数据库表Orders表为示例进行下演示

 1.先将Orders表的索引全部删除
 4.在OrderID上面创建聚集索引,索引列为OrderID  
代码如下:

create unique clustered index IX_OrderID on Orders(OrderID)

3.在Orders表上创建非聚集索引IX_OrderDate

create index IX_OrderDate on Orders(OrderDate)
4.设置查询分析器选中包含实际的执行计划(右键-->包含实际的执行计划),打开IO统计,并依次执行以下查询
代码如下:

set statistics io on
select * from Orders
select * from Orders where OrderDate

    
 
 

您可能感兴趣的文章:

  • SQL Server误区30日谈 第23天 有关锁升级的误区
  • SQL Server误区30日谈 第28天 有关大容量事务日志恢复模式的误区
  • SQL Server误区30日谈 第17天 有关页校验和的误区
  • SQL Server误区30日谈 第29天 有关堆碎片的误区
  • SQL Server误区30日谈 第25天 有关填充因子的误区
  • SQL Server误区30日谈 第8天 有关对索引进行在线操作的误区
  • SQL Server误区30日谈 第6天 有关NULL位图的三个误区
  • SQL Server误区30日谈 第5天 AWE在64位SQL SERVER中必须开启
  • SQL Server误区30日谈 第7天 一个实例多个镜像和日志传送延迟
  • SQL Server误区30日谈 第22天 资源调控器可以调控IO
  • SQL Server误区30日谈 第16天 数据的损坏和修复
  • SQL Server误区30日谈 第3天 即时文件初始化特性可以在SQL Server中开启和关闭
  • SQL Server误区30日谈 第21天 数据损坏可以通过重启SQL Server来修复
  • SQL Server误区30日谈 第10天 数据库镜像在故障发生后 马上就能发现
  • SQL Server误区30日谈 第27天 使用BACKUP WITH CHECKSUM可以替代DBCC CheckDB
  • SQL Server误区30日谈 第1天 正在运行的事务在服务器故障转移后继续执行
  • SQL Server误区30日谈 第9天 数据库文件收缩不会影响性能
  • SQL Server误区30日谈 第4天 DDL触发器就是INSTEAD OF触发器
  • SQL Server误区30日谈 第18天 有关FileStream的存储,垃圾回收以及其它
  • SQL Server误区30日谈 第11天 镜像在检测到故障后瞬间就能故障转移
  • SQL效率提升之一些SQL编写建议并有效利用索引
  • sql server对索引的使用
  • 导致SQL Server索引不可用的几种Sql语句写法
  • SQL学习笔记八 索引,表连接,子查询,ROW_NUMBER
  • SQL Server 索引结构及其使用(一)--深入浅出理解索引结构第1/4页
  • :[Microsoft][ODBC SQL Server Driver]无效的描述符索引 如何解决?
  • 提升SQL Server速度 整理索引碎片
  • sql视图创建索引的方法
  • 找出所有非xml索引并重新整理的sql
  • SQL_Server全文索引的用法解析
  • SQL Server 索引结构及其使用(二) 改善SQL语句第1/3页
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • java命名空间java.sql接口statement的类成员方法: executeupdate定义及介绍
  • 请问,这是什么错误!java.sql.SQLException: [Microsoft][ODBC SQL Server Driver][Named Pipes]??????? SQL Server?虽然分少,但一定给,只要您是前5名回复者中最好的以为!
  • java命名空间java.sql接口connection的类成员方法: nativesql定义及介绍
  • SQL查询分析工具 SQL Workbench/J
  • java命名空间java.sql接口preparedstatement的类成员方法: executeupdate定义及介绍
  • oracle导出sql语句的结果集和保存执行的sql语句(深入分析)
  • java命名空间java.sql接口rowid的类成员方法: getbytes定义及介绍
  • SQL Server统计SQL语句执行时间的脚本
  • java命名空间java.sql接口ref的类成员方法: getbasetypename定义及介绍
  • SQL客户端软件 PKLite SQL Client
  • java命名空间java.sql接口databasemetadata的类成员方法: getsqlkeywords定义及介绍
  • SQL语句实现SQL Server 2000及Sql Server 2005日志收缩(批量)
  • java命名空间java.sql接口rowid的类成员方法: tostring定义及介绍
  • SQL客户端管理工具 SQuirreL SQL Client
  • java命名空间javax.sql.rowset接口joinrowset的类成员方法: getwhereclause定义及介绍
  • 如何处理此错误:java.sql.SQLException: [Microsoft][ODBC SQL Server Driver]没有执行可选特性
  • java命名空间java.sql接口statement的类成员方法: execute定义及介绍
  • sql2005 大数据量检索分页的sql代码
  • java命名空间java.sql接口resultset的类成员方法: getcursorname定义及介绍
  • 如何实现连接一次数据库,提交多个sql语句。(sql的批处理)
  • java命名空间java.sql接口resultsetmetadata的类成员方法: getcolumntype定义及介绍
  • 微软网站下载的Ms SQL Server2000 JDBC Driver,必须用英文版的SQL server2000吗?




  • 特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3