SQL SERVER 2014 下IF EXITS 居然引起执行计划变更的案例分享
这个问题是在SQL SERVER 2005 升级到SQL SERVER 2014的测试过程中一同事发现的。我觉得有点意思,遂稍微修改一下脚本展示出来,本来想构造这样的一个案例来演示,但是畏惧麻烦,遂直接贴上原表,希望Leader不要叼我(当然个人觉得真没啥,两张表名而已,真泄露不了啥信息)。
脚本如下所示,非常简单的一段SQL语句,我将其分为SQL1、SQL2、SQL3. 其实SQL2、SQL3是差不多的,唯一的区别在于多了一个IF EXISTS
DECLARE @Operation_Code CHAR(3) ,
@FNCardList VARCHAR(1000) ,
@RollList VARCHAR(1000) ,
@White VARCHAR(20) ,
@OneMinute VARCHAR(20) ,
@Operator VARCHAR(20) ,
@Is_NoWait BIT ,
@HoldCards VARCHAR(3000);
SELECT @Operation_Code = '999' ,
@FNCardList = 'A15309913' ,
@RollList = 'A15309913';
--SQL 1
DECLARE @FNCardTable TABLE ( Iden INT, FN_Card CHAR(9) );
INSERT INTO @FNCardTable
SELECT Iden ,
[No]
FROM PUBDB.dbo.udf_ConvertStrToTable(@FNCardList, ',') a;
--SQL 2
SELECT 1
FROM dbo.fnRepairOperation a WITH ( NOLOCK )
INNER JOIN @FNCardTable b ON CHARINDEX(b.FN_Card, a.FN_Card) > 0
INNER JOIN dbo.fnJobTraceHdr c WITH ( NOLOCK ) ON c.FN_Card = b.FN_Card
AND c.Current_Department = a.Current_Department
WHERE a.Check_Time IS NULL
AND a.Is_Ignore = 0;
PRINT ( @Operation_Code );
--SQL 3
IF EXISTS ( SELECT 1
FROM dbo.fnRepairOperation a WITH ( NOLOCK )
INNER JOIN @FNCardTable b ON CHARINDEX(b.FN_Card,
a.FN_Card) > 0
INNER JOIN dbo.fnJobTraceHdr c WITH ( NOLOCK ) ON c.FN_Card = b.FN_Card
AND c.Current_Department = a.Current_Department
WHERE a.Check_Time IS NULL
AND a.Is_Ignore = 0 )
BEGIN
RAISERROR('返回错误!', 16, 1);
RETURN;
END;
在SQL SERVER 2005的环境中,整个批处理的SQL执行只需要不到1秒的样子。我们也能看到执行计划的COST对比值为0%,99%,1%。
在SQL SERVER 2014(SQL Server 2014 - 12.0.2000.8 Standard Edition )中执行时间突然变成了4分41秒。 最奇怪的是查询计划的COST比值依然为1%,99%,0%。实际测试发现这个COST的比值是不准确的。因为单独执行SQL1、SQL2只需要一秒。但是执行SQL3就需要4分多钟。(当然SQL SERVER 2005 与SQL SERVER 2014的数据,索引是一致的,细心的人会注意下面提示缺少索引,加上这个索引依然慢的出奇,这个影响因素完全可以忽略)
SQL 2的实际执行计划如下所示
SQL 3的实际执行计划如下所示
另外,表dbo.fnRepairOperation的记录数有332553,dbo.fnJobTraceHdr 的记录数为110058。表变量@FNCardTable记录数为1.对比执行计划,我们可以看到两者的Nested Loops的外部表变化了,从表变量@FNCardTable变成了dbo.fnRepairOperation
我们先来看看SQL2执行计划里面的一些详细信息,我们可以看到外边循环表为@FNCardTable,循环次数为1(Actual Number of Rows 值为1),内部循环表为dbo.fnJobTraceHdr,循环次数为1(Number of Executions为1),符合条件的记录集数据为1条(Actual Number of Rows 值为1)
那么再来看SQL3, 外部循环表变为dbo.fnRepairOperation,它走表扫描(Table Scan),循环次数为432(Actual Number of Rows),内部循环表为dbo.fnJobTraceHdr, 走索引扫描,总共循环了47545056次,这个值怎么来的呢? 因为内部循环表中符合记录数为110058(表dbo.fnJobTraceHdr的记录数), 110058*432 = 47545056,也就是说总共循环了四千七百多万次。 偶的神啊。难怪如此之慢。起初,我以为是统计信息不准确导致数据库优化器选择了错误的执行计划,于是我更新了这两个表的统计信息,甚至连索引也重建了。结果还是如此。看来的确是优化器没有选择最优的执行计划。但是没有IF EXITS它又是正常的, 加了IF EXITS后执行计划就变成这个鸟样。说不清是优化器的bug还是算法问题所导致。
那么怎么解决这个问题,可以用联接提示(HASH JOIN HINT)指定SQL语句走HASH JOIN,此时批处理的SQL语句可以1秒出来。另外就是改写该SQL语句的写法。在此不做过多阐述
IF EXISTS ( SELECT 1
FROM dbo.fnRepairOperation a WITH ( NOLOCK )
INNER JOIN @FNCardTable b ON CHARINDEX(b.FN_Card,
a.FN_Card) > 0
INNER HASH JOIN dbo.fnJobTraceHdr c WITH ( NOLOCK ) ON c.FN_Card = b.FN_Card
AND c.Current_Department = a.Current_Department
WHERE a.Check_Time IS NULL
AND a.Is_Ignore = 0 )
BEGIN
RAISERROR('部分卡中有 班长新增加的工序或 回修工序,请联系一下工艺员和当班班长!', 16, 1);
RETURN;
END;
其实这个案例也间接验证了嵌套循环连接,随着数据量的增长,这种方式对性能的消耗将呈现出指数级别的增长。
SQL SERVER 2014 下IF EXITS 居然引起执行计划变更的案例分享的更多相关文章
- 小心SQL SERVER 2014新特性——基数评估引起一些性能问题
在前阵子写的一篇博文"SQL SERVER 2014 下IF EXITS 居然引起执行计划变更的案例分享"里介绍了数据库从SQL SERVER 2005升级到 SQL SERVER ...
- 第16/24周 SQL Server 2014中的基数计算
大家好,欢迎回到性能调优培训.上个星期我们讨论在SQL Server里基数计算过程里的一些问题.今天我们继续详细谈下,SQL Server 2014里引入的新基数计算. 新基数计算 SQL Serve ...
- SQL Server 2014 BI新特性(一)五个关键点带你了解Excel下的Data Explorer
Data Explorer是即将发布的SQL Server 2014里的一个新特性,借助这个特性讲使企业中的自助式的商业智能变得更加的灵活,从而也降低了商业智能的门槛. 此文是在微软商业智能官方博客里 ...
- SQL Server 2014新特性:五个关键点带你了解Excel下的Data Explorer
SQL Server 2014新特性:五个关键点带你了解Excel下的Data Explorer Data Explorer是即将发布的SQL Server 2014里的一个新特性,借助这个特性讲使企 ...
- SQL Server 2014 Database Mail重复发送邮件特殊案例
在一数据库服务器(Microsoft SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64))发现有个作业调用Database Mail发送邮件时, ...
- 看完SQL Server 2014 Q/A答疑集锦:想不升级都难!
看完SQL Server 2014 Q/A答疑集锦:想不升级都难! 转载自:http://mp.weixin.qq.com/s/5rZCgnMKmJqeC7hbe4CZ_g 本期嘉宾为微软技术中心技术 ...
- 谈谈我的微软特约稿:《SQL Server 2014 新特性:IO资源调控》
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 撰写经历(Experience) 特约稿正文(Content-body) 第一部分:生活中资源 ...
- SQL Server 2014新特性探秘(1)-内存数据库
简介 SQL Server 2014提供了众多激动人心的新功能,但其中我想最让人期待的特性之一就要算内存数据库了.去年我再西雅图参加SQL PASS Summit 2012的开幕式时,微软就宣布 ...
- SQL Server 2014新特性探秘(2)-SSD Buffer Pool Extension
简介 SQL Server 2014中另一个非常好的功能是,可以将SSD虚拟成内存的一部分,来供SQL Server数据页缓冲区使用.通过使用SSD来扩展Buffer-Pool,可以使得大量随 ...
随机推荐
- 异步Promise实现
简介 异步回调的书写往往打乱了正常流的书写方式,在ECMAScript 6中实现了标准的Promise API,旨在 解决控制回调流程的问题. 简单的实现了Promise API: (function ...
- 主机巡检脚本:OSWatcher.sh
主机巡检脚本:OSWatcher.sh 2016-09-26更新,目前该脚本只支持Linux操作系统,后续有需求可以继续完善. 注意: 经测试,普通用户执行脚本可以顺利执行前9项检查: 第10项,普通 ...
- SwitchButton 开关按钮 的多种实现方式
刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心. 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果. 起初我在android上我只会 ...
- 11.struts2文件上传
文件上传 1.上传单个文件 2.上传多个文件 1.上传单个文件 实现步骤: (1)导入一个Jar包:commons-io-1.3.2.jar.只所以要导入这个Jar包,是因为要用到一个工具类Fil ...
- 测试为什么Low
你从来没有因为一个歌手不会写曲填词而说歌手很Low! 你从来没有因为一个演员不会摄影.唱歌而说演员很Low! 你从来没有因为一个记者不会摄影,拍照而说记者很Low! 你从来没有因为一个美食家不会烧菜, ...
- “SqlDateTime 溢出。必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间。”
原因: .NET中 DateTime最小值为: 0001-1-1 0:00:00 数据库中DateTime最小值为: 1753-1-1 0:00:00, 很明显:.NET中的最小值超出了数据库时间类 ...
- iOS的一些面试题分析总结(1)
本篇主要说一下多线程的东西,因为东西比较多,所以直接拿出一整个篇幅来说它了. 3. 多线程的底层实现? 1.先说一下什么是进程,什么是线程.什么是多线程. 进程是资源分配的单位,线程是调度运行的基本单 ...
- clr enabled Server Configuration Option
在SQL Server中启用CLR,可以执行下面SQL语句: EXEC sp_configure 'clr enabled'; '; RECONFIGURE; Source Code
- 初入网络系列笔记(1)TCP/IP基础
一.借鉴说明,本博文借鉴以下博文 1.BlueTzar,TCP/IP四层模型, http://www.cnblogs.com/BlueTzar/articles/811160.html 2.叶剑峰,漫 ...
- 第一篇:Entity Framework 简介
先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发O ...







