前言

上一篇我们分析了查询Hint的用法,作为调优系列的最后一个玩转模块的第一篇。有兴趣的可以点击查看:SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)

本篇继续玩转模块的内容,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析。

闲言少叙,进入本篇的内容。

技术准备

数据库版本为SQL Server2012,利用微软的以前的案例库(Northwind)进行分析,部分内容也会应用微软的另一个案例库AdventureWorks。

相信了解SQL Server的朋友,对这两个库都不会太陌生。

误区纠正

在开始本篇文章主题内容之前,先纠正一些关于新手对于数据库调优的误区。也希望在日常应用解决问题的时候,切记道听途说,人云亦云,毛爷爷说过的:实践是检验真理的唯一标准。

两个误区:

1、当在查询计划中发现了表扫描(Table Scan),就仿佛找到了病根一样,就想搞掉它,因为很多过来人都说过这种方式是性能很烂,而搞掉它的方式就是上索引,而且认为有了索引的就会快很多。

2、SQL Server语句优化就是创建索引,而创建索引就更简单了,找找查询语句,看看Where条件后...有几个筛选条件,创建几个非聚集索引就可以。

来看第一个问题:关于表扫描(Table Scan)是否真像传说的性能那么差劲!

首先,我们知道比较查询语句性能的优越性,无非就几个关键指标:运行IO、运行时间、消耗:CPU、Memory、编译时间等。

来看,以下语句,完全相同的表结构、表数据,不同的是一张表是堆表,一张是加了聚集索引的表,我们来开启两个回话进行测试比较。

堆表查询:

SET STATISTICS IO ON
--新建个测试表
SELECT * INTO NewOrders FROM Orders
--先清空缓存数据
DBCC DROPCLEANBUFFERS
GO
SELECT * FROM NewOrders
SET STATISTICS IO OFF

存在聚集索引的测试表查询:

SET STATISTICS IO ON
--新建个测试表
SELECT * INTO NewCLOrders FROM Orders
--添加聚集索引
CREATE CLUSTERED INDEX CL_OrderID ON NewCLOrders (OrderID desc)
GO
--先清空缓存数据
DBCC DROPCLEANBUFFERS
GO
SELECT * FROM NewCLOrders
SET STATISTICS IO OFF

这样对比的原因是:很多人认为数据库优化的方式就是加上索引,并且认为查找(Seek)就比扫描好(Scan)。

这样可以肯定的堆表采用的为表扫描(Table Scan),而后者则就是通过聚集索引扫描(Index Scan)

先来看IO的两者对比:

先来看看堆表的IO信息

堆表的表现:逻辑读取20次,预读2次,这里预读次数的多少其实是影响性能的重要指标,因为它是直接从磁盘中读取,所以性能最差,当然SQL Server此处采用并行处理,而且第一次读取数之后就缓存到内存中,防止再次的磁盘交互。

再来看聚集索引表的IO信息

采用聚集索引的表,逻辑IO为23次,预读飙升至22次。

相比而言:

相同的查询语句,堆表的查询逻辑读取次数为20次、预读2次,没有物理读...,而用聚集索引的表逻辑读为23次、预读22次!还有统计信息的不准确导致的物理读取1次!....所以相比堆表的SCAN是不是性能好很多。

当然,要再深入点分析,其实这两者不同的原因很简单:采用了聚集索引的表因为其存储的结构(B-Tree)的方式,所以逻辑IO肯定要多3,因为从索引根节点至叶子节点,也就是需要经过三个索引页,才能获取到数据页。

而预读的差距这么大的原因也是同样的原因:从堆表中获取数据是一段连续的数据页(确切的说是一次连续读取64个数据页<512KB>),而这时所有加上索引的表做不到的!通过索引只能依次读取一个数据页(8KB),这也是索引的局限性。

关于查询计划的逻辑读、预读、物理读等IO详细逻辑信息,可以参照我前面的文章,分析的很详细:SQL Server调优系列进阶篇(查询语句运行几个指标值监测)

接着我们再对比下执行时间,相信这个也是更为关注的:

看明白了吧,获取完全相同的数据量,堆表执行的时候耗时157毫秒,并且分析和编译没有占用时间,这个很简单,因为它是堆表,根本不需要根据统计信息进行优化和选择;而加上聚集索引的表就不一样了,需要根据索引的统计信息对T-SQL语句进行优化和编译,而这足足耗费了79毫秒,然后执行的时候还需要更多的预读IO,还有如果优化器没有优化到位的时候,还要造成额外的物理IO,所以它总耗费了298毫秒...

在我的测试表中只有八百多行的数据中就产生了如此的差距值..如果数据量多的话...性能就堪忧了....

关于CPU和内存值我就不截图了......上面我们分析了加了聚集索引了,就产生了查询优化器一系列的过程...而编译就是需要CPU资源的.....

通过上面的结果,我要表达的是:

首先,在我们所看到的查询计划中,不要一看到表扫描,就感觉这个运算符是很慢的,或者是很耗时的。更有甚者看到了就感觉问题出现在这上面,并且为很多人所唾弃为“万恶的表扫描”....

其次,请记住,在SQL Server中你所看到的任何一个运算符,都是在目前你所设定的环境中基本是最好的....更没有那个运算符好与那个运算符烂一说...诸如偏执的认为哈希连接就比嵌套循环要快...索引查找就比索引扫描要好等问题.....我们要做的就是合适的场景运用合适的处理方式,最优的顺应SQL Server性能。

再次,经过上述了问题的分析,也不要陷入另外一个极端的误区:表扫描就要比聚集索引扫描好!后续的文章中我会给你展示聚集索引比表扫描好的用处...在SQL Server的世界中,只有你真正的触摸的本质,才不会迷茫...才会看清一切所谓的教条调优都非绝对!

关于第二个问题的误区,其实是很多人的误区,误认为了非聚集索引的强大性,误以为在列中加上了索引就可以充分应用。本篇就不纠正了,可以参照我前面的文章,相信看完了基本也就懂了非聚集索引的利弊项,连接:SQL Server调优系列进阶篇(如何索引调优)

一、GROUP 提示 (Hints)

继续咱们本篇文章的内容,上一篇我们分析了查询的几个重要的Hints,本篇文章我们来看分组提示,分组查询也是我们在写T-SQL语句经常用到的,关于分组的运算符也有两个:Order Group和Hash Group。其实关于排序一直也是数据库中最为头疼的运算。这个运算符也是消耗比较大的,相当的耗内存,如果数据量较大的话,SQL Server处理的方式也是通过哈希算法进行优化。

当然,关于分组查询运算符分解,看以参照基础篇中的文章:SQL Server调优系列基础篇(常用运算符总结)

来看个例子:

SELECT CustomerID,MAX(OrderDate)
FROM Orders
GROUP BY CustomerID

上面的查询语句,我们想获取出每个订单的最大订单日期。

通过查询计划我们可以推测出肯定在CustomerID列存在索引,这样SQL Serer能直接利用这个进行排序,但是即便如此消耗还是飙升到56%....然后通过再加上一个流聚合计算出最大订单日期。

当然,此方式也是SQL Server认为的一种最优方式,但是如果数据量多的话,此种方式将会造成内存严重的消耗。

所以,我们可以采用GROUP Hint进行提示,将其更改为Hash 分组..代码如下:

SELECT CustomerID,MAX(OrderDate)
FROM Orders
GROUP BY CustomerID
OPTION(HASH GROUP)

当然,此处可能并不是一个最优的方式,只是为了演示,但是如果基础数据量增大的话,我也相信SQL Server会自动的更改为哈希匹配的方式进行。

、组合提示 (Hints)

大部分情况下,我们所写的T-SQL语句并不是简单的,有很多的各种嵌套查询进行,如果这种查询语句,我们的提示(Hints)就可能不是单一的。

我们来看如此方式该如何进行指导。先来看个简单的例子:

SELECT O.OrderID
FROM Customers C JOIN Orders O
JOIN Employees E
ON O.EmployeeID=E.EmployeeID
ON C.CustomerID=O.CustomerID
WHERE C.City=N'London' AND E.City=N'London'
OPTION(FORCE ORDER,HASH JOIN)

不仅仅如此,我们还可以手动给查询语句写查询计划。

也就是我们自己写的XML查询计划,让T-SQL语句就按照我们自定义的查询计划去进行,当然,这是大招了,我们留在最后使用。

参考文献

结语

此篇文章先到此吧,关于SQL Server调优工具Hint的使用还有很多内容,后续依次介绍,有兴趣的童鞋可以提前关注。

有问题可以留言或者私信,随时恭候有兴趣的童鞋加入SQL SERVER的深入研究。共同学习,一起进步。

文章最后给出前面几篇的连接,以下内容基本涵盖我们日常中所写的查询运算的分解以及调优内容项,皆为原创........

第一个基础模块注重基础内容的掌握,共分7篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划、掌握执行计划优化点,并一一列举了日常我们平常所写的T-SQL语句所会应用的运算符:

SQL Server调优系列基础篇

SQL Server调优系列基础篇(常用运算符总结)

SQL Server调优系列基础篇(联合运算符总结)

SQL Server调优系列基础篇(并行运算总结)

SQL Server调优系列基础篇(并行运算总结篇二)

SQL Server调优系列基础篇(索引运算总结)

SQL Server调优系列基础篇(子查询运算总结)

第二个进阶模块注重SQL Server执行T-SQL语句的时候一些内幕解析,共分为5篇文章完成,其中包括:查询优化器的运行方式、运行时几个优化指标值检测,统计信息、利用索引等一系列内容。通过这块内容让我们了解SQL Server为我们所写的T-SQL语句如何进行优化及运行的。

SQL Server调优系列进阶篇(查询优化器的运行方式)

SQL Server调优系列进阶篇(查询语句运行几个指标值监测)

SQL Server调优系列进阶篇(深入剖析统计信息)

SQL Server调优系列进阶篇(如何索引调优)

SQL Server调优系列进阶篇(如何维护数据库索引)

第三个玩转模块重点跟进特定的问题进行特定的提示(Hints),基于前两个模块进行的分析。

SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)

如果您看了本篇博客,觉得对您有所收获,请不要吝啬您的“推荐”。

SQL Server调优系列玩转篇二(如何利用汇聚联合提示(Hint)引导语句运行)的更多相关文章

  1. SQL Server调优系列玩转篇三(利用索引提示(Hint)引导语句最大优化运行)

    前言 本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲 ...

  2. SQL Server 调优系列玩转篇三(利用索引提示(Hint)引导语句最大优化运行)

    前言 本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲 ...

  3. SQL Server 调优系列玩转篇二(如何利用汇聚联合提示(Hint)引导语句运行)

    前言 上一篇我们分析了查询Hint的用法,作为调优系列的最后一个玩转模块的第一篇.有兴趣的可以点击查看:SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行) 本篇继续玩转模块 ...

  4. SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)

    前言 前面几篇我们分析了关于SQL Server关于性能调优的一系列内容,我把它分为两个模块. 第一个模块注重基础内容的掌握,共分7篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划. ...

  5. SQL Server 调优系列玩转篇一(如何利用查询提示(Hint)引导语句运行)

    前言 前面几篇我们分析了关于SQL Server关于性能调优的一系列内容,我把它分为两个模块. 第一个模块注重基础内容的掌握,共分7篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划. ...

  6. SQL Server调优系列基础篇

    前言 关于SQL Server调优系列是一个庞大的内容体系,非一言两语能够分析清楚,本篇先就在SQL 调优中所最常用的查询计划进行解析,力图做好基础的掌握,夯实基本功!而后再谈谈整体的语句调优. 通过 ...

  7. SQL Server调优系列基础篇(常用运算符总结——三种物理连接方式剖析)

    前言 上一篇我们介绍了如何查看查询计划,本篇将介绍在我们查看的查询计划时的分析技巧,以及几种我们常用的运算符优化技巧,同样侧重基础知识的掌握. 通过本篇可以了解我们平常所写的T-SQL语句,在SQL ...

  8. SQL Server调优系列基础篇(联合运算符总结)

    前言 上两篇文章我们介绍了查看查询计划的方式,以及一些常用的连接运算符的优化技巧,本篇我们总结联合运算符的使用方式和优化技巧. 废话少说,直接进入本篇的主题. 技术准备 基于SQL Server200 ...

  9. SQL Server调优系列基础篇(并行运算总结)

    前言 上三篇文章我们介绍了查看查询计划的方式,以及一些常用的连接运算符.联合运算符的优化技巧. 本篇我们分析SQL Server的并行运算,作为多核计算机盛行的今天,SQL Server也会适时调整自 ...

随机推荐

  1. java一点小的知识点

    1.在dos底下编译运行java文件时,若有包名,需要建立包名对应的文件夹,然后编译的时候写出包名:java.mypack.PackageDemo 2.代码中有包名的时候,自动创建文件夹并编译的方法: ...

  2. POJ 3276 Face The Right Way 反转

    大致题意:有n头牛,有些牛朝正面,有些牛朝背面.现在你能一次性反转k头牛(区间[i,i+k-1]),求使所有的牛都朝前的最小的反转次数,以及此时最小的k值. 首先,区间反转的顺序对结果没有影响,并且, ...

  3. 操作系统与c语言

      以下是根据看书后的理解做的总结:   最早,unix是使用汇编编写,但是非常简单.后来觉得汇编,换种机器又得重新用另外一种机器汇编重写,太麻烦.于是想设计一种通用的语言,到各种机器上都能运行 当时 ...

  4. Java经典实例:进阶版堆栈实现,支持任何对象类型

    支持任何对象类型,有更多的错误检查. package Stack; /** * Created by Frank */ public class MyStack<T> implements ...

  5. 推荐12个最好的 JavaScript 图形绘制库

    众多周知,图形和图表要比文本更具表现力和说服力.图表是数据图形化的表示,通过形象的图表来展示数据,比如条形图,折线图,饼图等等.可视化图表可以帮助开发者更容易理解复杂的数据,提高生产的效率和 Web  ...

  6. Wami Map Project – 开源的 OSM API 服务

    Wami 地图项目把 OSM 数据分享给所有的人,很容易使用.他们利用 MongoDB 的潜力进行大数据管理来实现从 OSM 数据来源搜索相关的数据.它们的 API 使人们有可能检索不同格式的 POI ...

  7. 2014年3月新鲜出炉的最佳 JavaScript 工具库

    一个 JavaScript 库是预先编写的 JavaScript 程序,用于简化 Web 应用程序开发,特别是对 Ajax 和其它 Web 为中心的技术.JavaScript 提供了多种方法,通过它来 ...

  8. 站长必备:10个好用的 WordPress 备份插件

    网站备份对于站长来说极其重要的.任何的事情都可能发生,这可能会导致你失去所有的辛勤工作:您的网站可能被黑客攻破,你可以安装一个了插件导致冲突,你的服务器可能被攻击,你可能在编辑文件时犯了一个错误等等, ...

  9. [deviceone开发]-毛玻璃效果示例

    一.简介 do_Bitmap组件可以把图片加载为内存里的Bitmap对象,能够对这个对象做各种图形化处理.目前只有3种处理,圆角,毛玻璃,灰度.以后会添加更多. 二.效果图 三.相关下载 https: ...

  10. 读《数据结构与算法 Javascript描述》 | 平淡无奇

    “平淡无奇”,一句话总结. 当初买这本书的原因,在意的是有没有什么令人惊喜的东西,特别是针对Javascript代码的奇思妙想,所以就买下了这本书. 在买的几本书里面,最先看的也是这一本,但看起目录就 ...