Home  >  Article  >  Database  >  SQLServer索引调优实践(2)

SQLServer索引调优实践(2)

WBOY
WBOYOriginal
2016-06-07 15:46:201090browse

继续,继续SQLServer索引调优实践。这次探讨一下索引覆盖 - SQL Server主要使用索引去查询你需要的数据,当索引包括所有的你请求查询的字段,SQL Server将不需要去在表中查询。这个概念称做索引覆盖。 SQLServer2005的Non-clustered INDEX增加了一个包含列(i

继续,继续SQLServer索引调优实践。这次探讨一下索引覆盖 - SQL Server主要使用索引去查询你需要的数据,当索引包括所有的你请求查询的字段,SQL Server将不需要去在表中查询。这个概念称做“索引覆盖”。

SQLServer2005的Non-clustered INDEX增加了一个“包含列(included column) ”选项。在 SQL Server 2005 中,可以通过将非键列添加到非聚集索引的叶级别来扩展非聚集索引的功能。通过包含非键列,可以创建覆盖更多查询的非聚集索引。当查询中的所有列都作为键列或非键列包含在索引中时,带有包含性非键列的索引可以显著提高查询性能。这样可以实现性能提升,因为查询优化器可以在索引中找到所有列值;不访问表或聚集索引数据,从而减少磁盘 I/O 操作。

但应避免添加不必要的列。添加过多的索引列(键列或非键列)会对性能产生不良影响,应该合理使用。和Clustered INDEX,或者组合索引,结合使用,扩大索引覆盖,但不大可能所有列都有索引覆盖,磁盘开销和数据insert updat时索引的重新计算的时间开销是巨大的。总之,合理的索引设计是建立在对各种查询的分析和预测上的,只有正确地使索引与程序结合起来,才能产生最佳的优化方案。

继续实践,先建个实验表 Table1:

SQLServer索引调优实践(2)

建两个索引:

1. 主键ID是Clustered INDEX

2. 非聚簇索引Non-Clustered INDEX建立在Age列上,包含列:Count。

CREATE NONCLUSTERED INDEX [cnt] ON [dbo].[table1]
(
    [Age] ASC
)
INCLUDE ( [Count])
ON [PRIMARY]

我们的测试SQL语句是:从10万条记录中取出4条记录,两种写法

1. SELECT * FROM table1 WHERE age 2. SELECT count FROM table1 WHERE age

看看运行效率如何:

磁盘IO和时间:

SQLServer索引调优实践(2)

实际执行计划:

SQLServer索引调优实践(2)

性能居然相差20多倍。为什么?

原来第二句Select Count在索引覆盖范围内,因为查询优化器可以在索引中找到所有列值;不访问表或聚集索引数据,从而减少磁盘 I/O 操作。而第一句Select * 选择了所有字段,其中有一个字段Name不在索引覆盖范围内(既不在聚簇索引列,也不在非聚簇索引覆盖列内),SQL Server可以在同一个查询中为一个表使用多个索引,并可以合并多个索引(使用联接算法),以便搜索关键字共同覆盖一个查询。查询分析优化器会自动进行选择, 上述执行计划就是优化的结果,依然比第二个index seek慢了20倍。

然后我又把sql改了一下,变成从10万条记录中取得大部分数据( 返回99900条),小于号改成大于号:

1. SELECT * FROM table1 WHERE age > 100;
2. SELECT count FROM table1 WHERE age > 100;

看看结果:

磁盘IO和时间:

SQLServer索引调优实践(2)

实际执行计划:

SQLServer索引调优实践(2)

依然是第二句索引覆盖的快,这是毋庸置疑的。但第一句执行计划有所不同,SQLServer查询分析优化器选择了不同的策略,改为聚簇索引扫描。上面说过了,SQL Server可以在同一个查询中为一个表使用多个索引,并可以合并多个索引(使用联接算法),以便搜索关键字共同覆盖一个查询。查询分析优化器会自动进行选择, 上述执行计划就是优化的结果。

为何结果集较小和结果集较大SQLServer选择的索引方案不同?

(From园友 高强:当 WHERE age 100时,由于记录数比较多,所以SQL SERVER 认为直接根据聚集索引叶级页面链表扫描页面得出结果更快。不管怎样,最终目的就是在相同结果集情况下,尽可能减少逻辑IO。)

看到这儿,恐怕喜欢用Select*的同学也要节制一下使用了,有时候SQLServer中Select*代价是很高的。当然类似这种SQL是没有问题的,(where exists (select * from ...)),因为SQLServer查询分析优化器会聪明的知道此Select*非彼Select*

数据库是一个很复杂的系统,即使你不是数据库专家,是应用开发人员,知道一点SQLServer内部更多的东西会有好处,而合理的索引设计是建立在对各种查询的分析和预测上的,只有正确地使索引与程序结合起来, 才能产生最佳的优化方案。

  • SQLServer索引调优实践

或许您对以下文章有兴趣:

  • 程序员办网站创业,几个问题你想好了吗?
  • CTO谈豆瓣网和校内网技术架构变迁
  • AJAX延迟异步加载边栏+服务器端缓存AJAX输出
  • 二级下拉菜单被遮住,css设置z-index在ie下没作用的问题解决办法
  • 简单JS实现走马灯效果的文字(无需jQuery)
  • jQuery和ExtJS的timeOut超时设置和event事件处理
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn