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,可以使得大量随 ...
随机推荐
- iOS编译FFmpeg、kxmovie实现视频播放 (转载)
由于FFmpeg开源框架的功能非常强大,可以播放的视频种类很多,同时添加第三方库kxmovie,实现视频播放,真的是爽爆了,因此今天来说一下关于FFmpeg在iOS手机上的一些配置过程,配置工具,还有 ...
- 如何设置UILabel中的字体的间距
cell.teacherDescriptionLabel.text = content; cell.teacherDescriptionLabel.textAlignment = NSTextAlig ...
- 1Z0-053 争议题目解析707
1Z0-053 争议题目解析707 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 707.Because of a logical corruption in the EMPLOY ...
- Node.js Express 路由文件分类
前言 基于上一篇Web Api Controller分类,在MVC中我们通常要按自己的业务来划分Controller层, 好处多多,那么Express框架作为Node.js的一款MVC框架,那么自然也 ...
- 在ASP.NET MVC 中获取当前URL、controller、action
一.URL的获取很简单,ASP.NET通用: [1]获取 完整url (协议名+域名+虚拟目录名+文件名+参数) string url=Request.Url.ToString(); [2]获取 虚拟 ...
- JavaScript代码模块化的正规方法
RequireJS-CommonJS-AMD-ES6 Import/Export详解 为什么起了一个这个抽象的名字呢,一下子提了四个名词分别是:RequireJS,CommonJS,AMD,ES6,答 ...
- identity与ASP.NET 模拟
默认情况下,ASP.NET应用程序以本机的ASPNET帐号运行,该帐号属于普通用户组,权限受到一定的限制,以保障ASP.NET应用程序运行的安全.但是有时需要某个ASP.NET应用程序或者程序中的某段 ...
- 墙裂推荐4款js网页烟花特效
以下是几款网页特效和一款软件: http://keleyi.com/keleyi/phtml/jstexiao/1.htm http://keleyi.com/keleyi/phtml/jstexi ...
- AutoMapper 使用实践
一. 使用意图 常常在开发过程中,碰到一个实体上的属性值,要赋值给另外一个相类似实体属性时,且属性有很多的情况.一般不利用工具的话,就要实例化被赋值实体B,然后再将实体A的字段一个个赋值给B的属性 ...
- es6 中增强的对象字面量
http://www.cnblogs.com/Wayou/p/es6_new_features.html 对象字面量被增强了,写法更加简洁与灵活,同时在定义对象的时候能够做的事情更多了.具体表现在: ...







