前言html
本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,一样,仍是但愿扎实掌握前面一系列的内容,才进入本模块的内容分析。算法
闲言少叙,进入本篇的内容。数据库
技术准备多线程
数据库版本为SQL Server2012,利用微软的之前的案例库(Northwind)进行分析,部份内容也会应用微软的另外一个案例库AdventureWorks。工具
相信了解SQL Server的朋友,对这两个库都不会太陌生。post
1、并行Hint提示 (MAXDOP N Hint)性能
在当前多核超线程的今天,并行运算已经不算什么稀罕了,因此在SQL Server中也有它本身的并行运算符,来充分的利用现有硬件资源,最大限度的提高运行效率。学习
在本系列中有两篇文章专门介绍关于SQL Server的并行运算,能够点击查看:SQL Server并行运算总结、SQL Server并行运算总结篇二优化
因此,在Hint中也给出了关于并行运算的提示:MAXDOP N Hint,这个Hint仍是常常用的,尤为索引操做的时候,为了缩短操做时间,咱们经常会最大限度的利用并行运算。url
另外,此Hint会优先于数据库级别的配置选项。也就说尽管在数据库中设置了MAXDOP 1(强制顺序运行),若是使用了此Hint也会忽略数据库设置的。
固然,并行运算虽然大部分状况能提高运行效率,可是也非绝对,咱们知道多线程的操做是须要维护线程之间的数据交换和执行顺序等,全部有时候多线程的执行并不必定会单线程效率高。
来看个例子:
SELECT [KEY],[DATA] FROM TestMaxDopTable WHERE DATA<1000 OPTION(MAXDOP 1) SELECT [KEY],[DATA] FROM TestMaxDopTable WHERE DATA<1000 OPTION(MAXDOP 4)
上面为串行运算,下面为4线程的并行运算。
固然,此处几线程运算能够本身设定,最大值推荐为当前系统配置的逻辑核数,固然设置大了也能够只不过没用罢了。
二、索引Hint提示 (INDEX Hint)
所谓的索引Hint提示,就是强制查询优化器为一个查询语句执行扫描或者使用一个指定的索引。
此方式,是咱们在调优中常常用到的一种方式,不少时候咱们建立的索引是失效的,固然,大部分状况下失效的缘由是建立索引不稳当致使的,可是有一些状况下,须要咱们来指导下T-SQL的运行方式,这时候就是索引Hint的使用场景了。
固然,这里能利用索引提示的前提就是当前表存在索引了,若是是堆表的状况,根本就谈不上了索引提示了,只能经过表扫描获取数据了。
来看看这个提示的用法:WITH(INDEX(N))
这里的N就是索引的在该表中索引顺序排序号了,来看一张表中的索引序列号:
SELECT * FROM SYS.indexes WHERE OBJECT_NAME(object_id)='Orders'
能够看到,该表中存在十个索引,依次排序以后,就是从1至10,第一个就是汇集索引(主键)了,而后是非汇集索引。
因此,咱们上面的N的值就是这个数字了,指定几就是要求用哪一个索引了。
来看个脚本:
SELECT OrderID,CustomerID FROM Orders WITH(INDEX(1)) WHERE ShipPostalCode=N'99362' SELECT OrderID,CustomerID FROM Orders WITH(INDEX(9)) WHERE ShipPostalCode=N'99362'
看到了,上面的例子中咱们选了两个索引:一个编号1的汇集索引PK_Orders,一个编号为9的非汇集索引了ShipPostalCode。固然,有兴趣也能够玩玩其它几个索引。
咱们顺便来分析下这个语句的索引用法:
首先从查询条件来看,咱们是根据ShipPostalCode进行查询,因此最好在该列中被索引所覆盖,这样在数据量大的状况下,查询优化器就能够采用索引查找(Index Seek)了,因此,这里咱们选择了第9个非汇集索引,恰巧覆盖该列值,从上面的查询计划也能够看出,采用该索引Hint提示后查询开销从69%提高至3%...可是因为这个非汇集索引没有包含CustomerID列,因此不得不又引入书签查找(key Lookup)来获取该列值,而且这个书签查找消耗还比较大:60%,因此最佳的方式就是将该索引Include进CustomerID列。
固然,此方式用起来可能很不爽,由于咱们在使用的时候须要查找当前表中的各个索引的排序号。
因此,咱们最推荐也是最经常使用的方式是这样:
WITH(INDEX('IndexName'))
就是咱们直接指定索引名称既能够,来看个例子:
SELECT OrderID,CustomerID FROM Orders WITH(INDEX(CustomersOrders)) WHERE ShipPostalCode=N'99362'
看起来,简单的多了,由于索引的名字咱们直接能看到,来看看咱们将这个查询语句指定到这个非汇集索引CustomersOrders上的执行计划。
来看看这个查询计划:丫的!.....查询开销直接飙升到100%......缘由很简单:这个非汇集索引和这个查询一毛钱关系....可是咱们却强制的指定该语句利用索引执行....
首先非汇集索引包含的列为:[OrderID],[CustomerID]
咱们要获取的值为按照ShipPostalCode进行筛选,因此要获取结果就必须按照这个非汇集索引进行一次扫描(Index Scan),这个还能够,毕竟非汇集索引都是有序进行的,可是为了进行过滤,就必须引入书签查找(Key Lookup)进行过滤,咱们知道书签查找为随机IO,消耗巨大,因此此次过滤就比如在整张表中随机的去查找数据同样,其实效率还不如来一次表扫描(Table Scan)的好,因此此开销飙升到95%!
上面的例子,也是不少新手容易犯的错误。
我记得在玩转模块的第一篇中,咱们提到过一个利用OPTIMIZE FOR Hint提示 解决一个引入参数而致使的执行计划评估不许的问题。
文章能够点击此处看到:SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)
咱们来回顾下:
--普通的查询语句 SELECT OrderID,OrderDate FROM Orders WHERE ShipPostalCode=N'51100' --参数化后的查询语句 DECLARE @ShipPostalCode NVARCHAR(50) SET @ShipPostalCode=N'51100' SELECT OrderID,OrderDate FROM Orders WHERE ShipPostalCode=@ShipPostalCode
彻底相同逻辑的查询语句,只是下面那个咱们经过参数进行了传值操做。
咱们只是加了一个参数,SQL Server将相同的查询语句,有之前的索引查找变成了索引扫描了!
消耗一会儿从46%提高到54%.....这也是咱们写的语句常常遇到的问题,由于不少状况下,咱们都是经过传参来实现该语句的重用性。
可是,为何加了参数使得查询性能变差,显然不是一个好的方式,在第一篇的玩转篇中,咱们的解决方式是经过OPTIMIZE FOR Hint提示解决。
这里,咱们再来看一个解决方式,也能够经过索引Hint来强制该语句指定按照给定的索引进行查找。
方法以下:
--参数化后的查询语句 DECLARE @ShipPostalCode NVARCHAR(50) SET @ShipPostalCode=N'51100' SELECT OrderID,OrderDate FROM Orders WITH(INDEX(ShipPostalCode)) WHERE ShipPostalCode=@ShipPostalCode
是否是一个很帅的方式。
但愿你能理解这些个方式的好处,算做抛砖引玉了。
结语
此篇文章先到此吧,到此玩转篇已经三篇了,关于SQL Server调优工具Hint的使用还有不少内容,后续依次介绍,有兴趣的童鞋能够提早关注。
有问题能够留言或者私信,随时恭候有兴趣的童鞋加入SQL SERVER的深刻研究。共同窗习,一块儿进步。
文章最后给出前面几篇的链接,如下内容基本涵盖咱们平常中所写的查询运算的分解以及调优内容项,皆为原创........
第一个基础模块注重基础内容的掌握,共分7篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划、掌握执行计划优化点,并一一列举了平常咱们日常所写的T-SQL语句所会应用的运算符:
第二个进阶模块注重SQL Server执行T-SQL语句的时候一些内幕解析,共分为5篇文章完成,其中包括:查询优化器的运行方式、运行时几个优化指标值检测,统计信息、利用索引等一系列内容。经过这块内容让咱们了解SQL Server为咱们所写的T-SQL语句如何进行优化及运行的。
SQL Server调优系列进阶篇(查询语句运行几个指标值监测)
第三个玩转模块重点跟进特定的问题进行特定的提示(Hints),基于前两个模块进行的分析。
SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)
SQL Server调优系列玩转篇二(如何利用汇聚联合提示(Hint)引导语句运行)
若是您看了本篇博客,以为对您有所收获,请不要吝啬您的“推荐”。