SQL Server 性能调优 之执行计划(Execution Plan)调优

SQL Server查询计划解读:从执行原理到性能优化实战 SQL Server查询计划是数据库优化的核心依据,本质是查询优化器基于成本模型(I/O、CPU、内存)计算出的最优执行路径快照。理解其生成机制需掌握统计信息、参数嗅探与计划缓存等底层原理;技术价值在于将模糊的‘慢SQL’问题转化为可量化、可验证的图形化诊断过程——通过运算符形状识别物理操作类型(如索引查找vs扫描),借助颜色区分资源瓶颈(绿色主I/O、黄色主CPU),结合实际行数与估计行数偏差定位统计失真。典型应用场景涵盖OLTP高并发调优、BI报表加速及遗留系统性能治理。本文聚焦实际执行计划分析,深入拆 阅读详情

执行计划中的三种 Join 策略

SQL Server 存在三种 Join 策略:Hash Join,Merge Join,Nested Loop Join。

Hash Join:用来处理没有排过序/没有索引的数据,它在内存中把 Join 两边数据(的关联key)分别建立一个哈希表。例如有以下的查询语句,关联的两张表没有建立索引,执行计划将显示为Hash Join。

SELECT
  sh.*
FROM
  SalesOrdHeaderDemo AS sh
JOIN
  SalesOrdDetailDemo AS sd
ON
  sh.SalesOrderID=sd.SalesOrderID
GO

Merge Join:用来处理有索引的数据,它比Hash Join轻量化。我们为前面两张表的关联列建立索引,然后再次上面的查询,执行计划将变更为Merge Join

CREATE UNIQUE CLUSTERED INDEX idx_salesorderheaderdemo_SalesOrderID ON SalesOrdHeaderDemo (SalesOrderID)
GO
CREATE UNIQUE CLUSTERED INDEX idx_SalesDetail_SalesOrderlID ON SalesOrdDetailDemo (SalesOrderID,SalesOrderDetailID)
GO

Nested Loop Join:在满足Merge Join的基础上,如果某一边的数据较少,那么SQL Server 会把数据较少的那个作为外部循环,另一个作为内部循环来完成Join处理。继续前面的例子为查询语句加上WHERE语句来减少 Join 一边的数据量,执行计划显示为Nested Loop Join。

SELECT
  sh.*
FROM
  SalesOrdHeaderDemo AS sh
JOIN
  SalesOrdDetailDemo AS sd
ON
  sh.SalesOrderID=sd.SalesOrderID
WHERE
  sh.SalesOrderID=43659

执行计划中的(table/index scan)的改进

在许多场合我们需要在一张包含许多数据的表中提取出一小部分数据,此时应当避免Scan,因为扫描处理会遍历每一行,这是相当耗时耗力的。下面我们来看一个例子:

SELECT
  sh.SalesOrderID
FROM
  SalesOrdHeaderDemo AS sh
JOIN
  SalesOrdDetailDemo AS sd
ON
  sh.SalesOrderID=sd.SalesOrderID
WHERE
  sh.OrderDate='2005-07-01 00:00:00.000'
GO


图中的红圈标出了table scan,并且执行计划也智能得建议建立索引。我们先尝试在SalesOrdHeader 表上建立一个索引:

CREATE UNIQUE CLUSTERED INDEX idx_salesorderheaderdemo_SalesOrderID ON SalesOrdHeaderDemo (SalesOrderID)
GO

然后再次执行相同的查询语句,执行计划变成以下的模样:


table scan 变为了 Index Scan,继续给另一张表也加上索引:

CREATE UNIQUE CLUSTERED INDEX idx_SalesDetail_SalesOrderlID ON SalesOrdDetailDemo (SalesOrderID,SalesOrderDetailID)
GO

执行计划发生以下的变化:


虽然不能说 Scan 比 Seek 差,但绝大多数的场合(尤其是在许多数据中查找少量数据时)Seek 是更好的选择。举例来说如果你有一个上亿条数据的表,你要取其中的100条,那么你应当保证其采用 Seek,但如果你需要取出其中绝大多数(比如95%)的数据时,Scan 可能更好。(有较权威的文章给出了这个阀值为30%,即取出超过30%数据时 scan 更高效;反之则 Seek 更好)

另外你可能注意到两张表上都建立了索引但一张表在执行计划中表现为 Clustered index scan,而另一张表现为 Clustered index seek,我们期待的不是两个 Clustered index seek 吗?这是因为前一张表没有断言(predicate),而后一张表通过 ON 关键字对SalesOrderID 进行了断言限制。

执行计划中的 Key Lookup

为了后续的示例,我们先在同一张表上建立两个不同的索引:

CREATE UNIQUE CLUSTERED INDEX idx_SalesDetail_SalesOrderlID ON SalesOrdDetailDemo (SalesOrderID,SalesOrderDetailID)
GO
CREATE NONCLUSTERED INDEX idx_non_clust_SalesOrdDetailDemo_ModifiedDate ON SalesOrdDetailDemo(ModifiedDate)
GO

执行以下的查询:

SELECT
  ModifiedDate
FROM SalesOrdDetailDemo
  WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

执行计划如下图,他利用了我们先前建立在 ModifiedDate 字段上的 Non-Clustered Index,生成为一个Index Seek 处理。


我们改造一下查询语句,SELECT 中多加两个字段:

SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID
FROM SalesOrdDetailDemo
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

执行计划如下图,基本没变:


上面选出的字段不是属于 Non-Clustered Index 就是属于 Clustered Index,如果再增加几个其他的字段呢?

SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID,
  ProductID,
  UnitPrice
FROM SalesOrdDetailDemo
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

乖乖,执行计划一下多了两个处理(Key Lookup, Nested Loop):


Key Lookup 是一个繁重的处理,我们可以使用关键字 WITH 来指定使用 Clustered Index,以此回避Key Lookup。

SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID,
  ProductID,
  UnitPrice
FROM SalesOrdDetailDemo WITH(INDEX=idx_SalesDetail_SalesOrderlID)
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO
执行计划应声而变成为一个 Clustered Index Scan:


前文提过 Scan 似乎也不是一个很好的处理,那么矮子里拔高个,使用 SET STATISTICS IO ON 来比较一下:

SET STATISTICS IO ON
GO

SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID,
  ProductID,
  UnitPrice
FROM SalesOrdDetailDemo
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID,
  ProductID,
  UnitPrice
FROM SalesOrdDetailDemo WITH(INDEX=idx_SalesDetail_SalesOrderlID)
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID,
  ProductID,
  UnitPrice
FROM SalesOrdDetailDemo WITH(INDEX=idx_non_clust_SalesOrdDetailDemo_ModifiedDate)
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

比较下来,采用了 clustered index 的查询表现最差,另外 SET STATISTICS IO 输出的数据中clustered index 的查询在 logical reads 上花费了更多的时间。

看起来采用 non-clustered index + Key Lookup 执行计划表现还不错,但如果能回避 Key Lookup 就完美了,我们来把 non-clustered index 修改一下,用 INCLUDE 关键字在索引中包含其他的字段:

DROP INDEX idx_non_clust_SalesOrdDetailDemo_ModifiedDate ON SalesOrdDetailDemo
GO
CREATE NONCLUSTERED INDEX idx_non_clust_SalesOrdDetailDemo_ModifiedDate ON SalesOrdDetailDemo(ModifiedDate)
INCLUDE
(
  ProductID,
  UnitPrice
)
GO

-- 清下缓存,仅用于开发环境!
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
GO
再次执行之前的查询:
SELECT
  ModifiedDate,
  SalesOrderID,
  SalesOrderDetailID,
  ProductID,
  UnitPrice
FROM SalesOrdDetailDemo
WHERE ModifiedDate='2005-07-01 00:00:00.000'
GO

这下完美了,因为我们的查询字段都包含在索引中,所以执行计划最终被优化为 Index Seek。


通过分析SQL语句的执行计划优化SQL(总结) NULL 博文链接:https://huangtut.iteye.com/blog/285494 立即下载

相关推荐

SQLServer性能调优之执行计划第一次实践

自从上一篇文章发出之后,收到了很朋友的关注。很多朋友要求多多实践,而不是纯粹的理论。确实,从打算出这个系列开始,我就本着实践的思想来进行的!执行计划可以辅助我们写出高效率的T-SQL代码,同时也可以找出现有T-SQL代码的问题,还可以监控数据库!当然,最后如何使用执行计划还是取决于我们自己了,但是不管怎么样,我们首先学会解析执行计划中所包含的信息,最快的学习方法就是实践。下面,我们就从一个实践开始。为了使得大家易于理解,这里的例子不会太复杂,随着课程的不断深入,后续的示例也会越来越复杂。同时,如果大家也想跟着一起动手实践,那么希望朋友们安装SQL2005或更高版本,同时记得安装Adventur

解决 SQL Server 中 CPU 使用率过高的问题

解决 SQL Server 中 CPU 使用率过高的问题

淡墨银痕的博客 8671

记录LeNet的硬件加速器设计(一)

LeNet的硬件加速器设计实现。

2301_81029398的博客 3543

sqlserver关于缺少索引的建议是怎么来的?

看sqlserver执行计划的时候有时会看到这样一行小绿字: 它会告诉你当前sql应该在哪些列上建索引(还有include列),建完之后能提升多少性能。对于特别复杂的sql,这个建议有时还是很方便的。那么这些数据是从哪查出来的? sqlserver有四个索引缺失相关的视图: sys.dm_db_missing_index_details sys.dm_db_missing_index_...

Hehuyi_In的博客 4779

vue高德地图POI关键字搜索定位

最近在项目中遇到了关于地图的问题,首先为了满足需求从而使用的是JSAPI为2.0版本的。需求是根据关键字搜索定位到该位置。值得注意的是在使用 AMap.Event.addListener时 Event一定要大写的E,不然页面会报错。在地图上定义一个输入框,根据输入的位置进行提示,然后点击后跳转到对应的位置并打点标记。JSAPI主要使用这两个。

YL 2131

3D Slicer中安装MedSAM插件

大家应该都读过这篇论文:《Segment Anything in Medical Images》这个插件便是该论文团队推出的在3D Slicer上使用的插件,可以分割医学图像的任何感兴趣区域。

m0_73719342的博客 2329

SQL语句优化流程

当确认了Parameter Sniffing问题后,会发现,根据某些变量值生成的执行计划,快和慢会相差很大,而根据另外一些变量生成的执行计划,性能在好和坏的时候,相差并不很大。例如当变量等于50000的时候,它用最好的Nested Loops执行计划,用时十几毫秒,用Hash Join的那个执行计划,也不过300多毫秒。这种方法的优点是,既能够让SQL Server做出有倾向性的执行计划,又能够保证SQL Server选择执行计划时候的自由度,所以得到的执行计划一般是比较好的。不是所有的视图都能建索引的。

dusang918的博客 499

Ambari 安装部署教程(手把手教学)【超级详细】

本文为读者提供了一套超详细的 Apache Ambari 安装部署教程,采用手把手教学方式,适合初学者及大数据运维人员。内容涵盖前期准备、环境配置、Ambari Server 与 Agent 安装、集群初始化配置、常见问题排查等全流程操作,确保用户能够顺利搭建稳定的 Hadoop 大数据平台管理系统。

Five的博客 1万+

博客7:数据库性能调优 - 执行计划与SQL优化

摘要:本文将深入探讨数据库性能调优的关键方面 - 执行计划与SQL优化。我们将了解什么是执行计划,如何查看执行计划以及如何基于执行计划进行SQL优化。

m0_61821405的博客 496

Qt5.15.7编译报错问题汇总:python2安装环境导致的问题

导致编译生成的:RegExpJitTables.h文件大小为0。RegExpJitTables.h 能生成且大小不为0KB。可以看到,正确的python路径,执行编译路径后。再执行 configure XXX…尝试直接改,将其改为正确的路径。

MusicScore的博客 1439

【WRF数据介绍第一期】静态地理数据介绍及下载

WRF数据介绍第一期:静态地理数据介绍及下载

WW、forever的博客 4809

SQL优化 之 执行计划分析(sql server 数据库)

执行计划是SQL Server查询优化器生成的指令集,描述了如何执行查询。通过分析执行计划,可以识别性能瓶颈并进行优化。

u013334925的博客 1318

Simulink实例--电动汽车充电站与微电网协同运行仿真

​电网负荷剧增:单站1000台车同时充电需150MW功率(超配电网容量30%)​能源孤岛问题:传统充电站仅作为单向负荷,无法参与电网调频​可再生能源消纳:光伏/风电波动导致充电站功率波动±40%​多目标矛盾:充电效率、电网稳定性、设备寿命的协同优化​节能效果:每百万辆车年节电1.8GWh​成本回收:投资回报周期<4年(IRR>25%)​减排效益:每年减少CO₂排放12万吨。

xiaoheshang_123的博客 329

SQL Server查询执行计划–查看计划

In the SQL Server query execution plans – Basics, we described the query execution plans in SQL Server and why they are important for performance analysis. In this article, we will focus on the method...

culuo4781的博客 4366

安装openclaw时出现npm error code ENOENT npm error syscall spawn git报错的解决方案

本文主要介绍了安装openclaw时出现npm error code ENOENT npm error syscall spawn git报错的解决方案,希望能对使用openclaw的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 12万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

SQL Server的执行计划(Execution Plans)

为了能够执行查询,SQL Server 数据库引擎必须分析该语句,以确定访问所需数据的最有效方法。此分析由称为查询优化器的组件处理。查询优化器的输入由查询、数据库架构(表和索引定义)和数据库统计信息组成。查询优化器的输出是查询执行计划,有时称为查询计划或执行计划。

Lion_Long的博客 5446

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

sql server 执行计划(execution plan)介绍

大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习。 什么是sql server 执行计划 sql server 执行计划的大致使用 学习计划   1.什么是sql server 执行计划   执行计划是查询优化器对我们提交的T-SQL查询请...

weixin_34348111的博客 1500

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SQL Server执行计划(2) - 如何查看执行计划

在上一篇文章中,我们详细描述了提交的 SQL Server 查询所经历的不同阶段以及 SQL Server 关系引擎如何处理它。SQL Server 关系引擎生成执行计划,SQL Server 存储引擎执行请求的数据检索或修改过程。在本文中,我们将讨论 SQL Server 执行计划的不同类型和格式。 执行计划类型 SQL Server 执行计划是已提交查询的执行路线图的图形表示,SQL Server 查询优化器将遵循该路线图。SQL Server 为我们提供了两种主要类型的执行计划。 预估执行计划 :

信天翁的博客 1万+

SQL Server Query Execution Plan Analysis

<br />当需要分析某个查询的效能时,最好的方式之一查看这个查询的执行计划。执行计划描述SQLServer查询优化器如何实际运行(或者将会如何运行)一个特定的查询。<br />查看查询的执行计划有几种不同的方式。它们包括:<br />SQL Server查询分析器里有一个叫做”显示实际执行计划”的选项(位于”查询”下拉菜单中)。如果打开了这个选项,那么无论何时在查询分析器中运行一个查询,都会得到一个显示在单独窗口的查询执行计划(以图形的格式)。<br />如果只是想看下执行计划而不想运行查询,那么可以选择

鱼汤的技术资料库 2745

Execution Plan 执行计划介绍

后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载. 下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 查询优化器对输入的 T-SQL 查询语句通过"计算"而选择出效率最高的一种执行方案,这个执行方案就是执行计划. 执行计划可以告诉你这个查询将会被如何执行或者已经被如何执行过,可以通过执行计划...

u014712365的博客 258

SQL Server SELECT执行原理:从语法解析到执行计划全链路拆解

SELECT语句是关系型数据库最基础的查询操作,其背后涉及语法分析、语义绑定、查询优化与物理执行四大核心阶段。理解这一过程,需掌握SQL Server如何通过Parser验证T-SQL结构合法性、Algebrizer完成权限校验与数据类型推导、Query Optimizer基于开销模型决策执行策略(如trivial plan触发条件),以及Execution Manager协同存储引擎完成数据读取。该机制不仅决定了查询性能基线,更直接影响索引有效性、参数化复用率与执行计划稳定性。在高并发OLTP或报表类场景

baochuanying9531的博客 421

SQL Server执行计划面试问题

In this article, we will discuss a few very common questions that you may be asked during a SQL Server administrator or developer technical job interview. 在本文中,我们将讨论一些非常常见的问题,在SQL Server管...

culuo4781的博客 640
上一篇: 何时使用 Parallel.ForEach,何时使用 PLINQ
下一篇: SQL Server 性能调优2 之索引(Index)的建立
sqlchen
博客等级 码龄24年 10粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值