前言

本节我们开始讲讲这一系列性能比较的终极篇IN VS EXISTS VS JOIN的性能分析,前面系列有人一直在说场景不够,这里我们结合查询索引列、非索引列、查询小表、查询大表来综合分析,简短的内容,深入的理解,Always to review the basics。

IN VS EXISTS VS JOIN性能分析

我们继续创建测试表,如下

CREATE SCHEMA [compare]
CREATE TABLE t_outer (
id INT NOT NULL PRIMARY KEY,
val1 INT NOT NULL,
val2 INT NOT NULL
)
CREATE TABLE t_inner (
id INT NOT NULL PRIMARY KEY,
val1 INT NOT NULL,
val2 INT NOT NULL
)
CREATE TABLE t_smallinner (
id INT NOT NULL PRIMARY KEY,
val1 INT NOT NULL,
val2 INT NOT NULL
)
GO
CREATE INDEX ix_outer_val1 ON [compare].t_outer (val1)
CREATE INDEX ix_inner_val1 ON [compare].t_inner (val1)
CREATE INDEX ix_smallinner_val1 ON [compare].t_smallinner (val1)

创建三个表即t_outer、t_inner、t_smaler同时将三个表中的列val1创建索引而对t_smaller表中的val2未创建索引,下面我们开始插入测试数据

USE TSQL2012
GO DECLARE @num INT
SET @num =
WHILE @num <=
BEGIN
INSERT
INTO [compare].t_inner
VALUES (@num, RAND() * , RAND() * )
INSERT
INTO [compare].t_outer
VALUES (@num, RAND() * , RAND() * )
SET @num = @num +
END
GO

对t_inner和t_outer分别插入10万条随机数据,然后去取t_outer表中最后100条数据插入到表t_smaller中

USE TSQL2012
GO INSERT
INTO [compare].t_smallinner
SELECT TOP
ROW_NUMBER() OVER (ORDER BY id DESC),
val1,
val2
FROM [compare].t_outer
ORDER BY
id DESC
GO

表以及测试数据创建完毕,下面我们开始一个一个分析。

(1)IN性能分析(在大表上查询索引列val1)

SELECT  val1
FROM [compare].t_outer o
WHERE val1 IN
(
SELECT val1
FROM [compare].t_inner
)

我们将上述查询计划示意图过程简短描述成如下:

整个查询耗费时间如下:

此时整个查询时间耗费70毫秒,对于10万条数据来说算是非常快的了,因为此时我们在t_inner表和t_outer表上的列val1都建立了索引,所以此时选择Stream Aggregate来进行过滤去除对于t_outer表上的val1中对应的t_inner表上的val1的重复值。到底是怎么去除重复的呢?它会记录重复的最后一个值,当再有值被找到,此时将无法通过。上述之所以查询非常快的原因在于输入行已经提前进行了预排序。最后得到的两个表的结果集进行Merge Join,进行Merge Join时,它会初始化一个变量并将指针指向加入的两个列的最小值,然后返回两个表结果集中匹配到的值,然后将指针指向下一个两个索引列中的存在的值,否则跳过不匹配的值,一直到完成,当进行如下查询时和上述查询计划是一致的。

SELECT  o.val1
FROM [compare].t_outer o
JOIN (
SELECT DISTINCT val1
FROM [compare].t_inner
) i
ON i.val1 = o.val1

(1)EXISTS性能分析(在大表上查询索引列val1)

我们通过如下查询来分析EXISTS

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT val1
FROM [compare].t_outer o
WHERE EXISTS (
SELECT
FROM [compare].t_inner s
WHERE s.val1 = o.val1
)

上述我们能够很清楚的知道EXISTS查询计划和IN是一致的,信不信由你,当下次面试再问二者性能的问题时,可千万别说EXISTS性能高于IN,这是错误的,上述我们已经分析得出其实是一样的。如果你仍是觉得EXISTS性能高于IN,请用事实证明。上述我们一直演示的是查询索引列val1,那要是在非索引列val2上查询会怎样呢。

(2)IN性能分析(在大表上查询非索引列val2)

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT val2
FROM [compare].t_outer
WHERE val2 IN
(
SELECT val2
FROM [compare].t_inner
)

我们再来分析下查询计划

我们重点看看Hash Match(Left Semi Join),此时对t_outer表上的值建立哈希表,然后t_inner表中每一行值来探测该哈希表,接着通过Left Semi Join来匹配值,如果匹配到值,此时匹配到的值会立即从哈希表中移除,最终哈希表将逐渐缩小。接着我们再来看EXISTS。

(2)EXISTS性能分析(在大表上查询非索引列val2)

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT val2
FROM [compare].t_outer o
WHERE EXISTS (
SELECT
FROM [compare].t_inner s
WHERE s.val2 = o.val2
)

此时我们看到无论是查询索引列还是非索引列EXISTS和IN在查询计划和耗费时间几乎完全是一致的,到这里我们针对讨论的是大表10万条数据,下面我们会讨论在小表t_smaller中有关二者的查询。接下来我们看看利用JOIN在索引列上进行查询。

(2)JOIN性能分析(在大表上查询非索引列val2)

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT o.val2
FROM [compare].t_outer o
JOIN (
SELECT DISTINCT val2
FROM [compare].t_inner
) i
ON i.val2 = o.val2

我们看到查询耗费时间和查询计划都和EXISTS、IN有不同,我们再来看看执行的顺序。

与上述不同的是JOIN在两个表联合之前首先进行了Hash Match(Aggregate),也就是说和EXISTS、IN不同之处在于重复值的处理,对于EXISTS、IN来说直接将两个表进行联合然后通过LEFT Semi Join来进行过滤重复值,在此通过哈希匹配中的聚合来过滤去除重复值val2,Hash Match(Aggregare)建立了一个唯一的哈希表,所以很容易来过滤重复值,因为有重复值过来时唯一哈希表能够探测到会产生值冲突,此时重复值都不会进入哈希表中。查询引擎通过哈希表来探测t_outer中的值,最终返回匹配的值。普遍想法是JOIN性能比EXISTS、IN性能要好,上述我们在查询非索引列时其查询开销和耗费时间却比EXISTS、IN要高,所以相对来说JOIN对于查询非索引列时其性能是比较低效的。接下来我们继续来看看查询小表t_smaller的情况。

(3)IN性能分析(在小表上查询索引列val1)

我们查询小表看看关于IN的查询情况是怎样的呢

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT val1
FROM [compare].t_outer o
WHERE val1 IN
(
SELECT val1
FROM [compare].t_smallinner
)

因为数据只有100条的小表其查询耗费时间当然非常少且查询速度非常快,我们重点看看其查询计划。此时合并结果集时不再是Merge Join代替的是遍历整个索引,它会扫描整个t_smaller表来过滤重复值,当然仅仅只是查找在t_outer表上创建的索引列val1且是通过索引查找的方式。数据量小所以即使是遍历整个索引也是非常快的。在EXISTS和JOIN中其执行计划结果和上述一致,下面我们再来看看查询非索引列的情况。

(4)IN性能分析(在小表上查询非索引列val2)

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT val2
FROM [compare].t_outer o
WHERE val2 IN
(
SELECT val2
FROM [compare].t_smallinner
)

此时我们看到查询小表上非索引列val2和大表上的非索引列val2执行计划几乎是一样的,有一点不同的是在大表中建立哈希表是在外部查询表中,在这里却是在子查询表中建立哈希表,这就是查询引擎高明的地方,数据少时在小表上建立哈希表一来在哈希表中存储的数据少即占用内存少,二来当匹配到值时就缩减哈希表的大小。我们再来看看JOIN的情况。

(4)JOIN性能分析(在小表上查询非索引列val2)

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT o.val2
FROM [compare].t_outer o
JOIN (
SELECT DISTINCT val2
FROM [compare].t_smallinner
) i
ON i.val2 = o.val2

因为数据量小所以耗费时间短,这个我们可以忽略不看,我们还是看看查询计划情况,此时利用Distinct Sort来消除重复的数据而不是利用哈希表,它会一次次的重建,可想而知性能的低下。分析到这里为止,我们看到在SQL Server中其实在有些情况下IN、EXISTS的查询性能是高于JOIN的。还不相信吗,我们再来看一个例子。

USE TSQL2012
GO SET STATISTICS IO ON
SET STATISTICS TIME ON SELECT val2
FROM [compare].t_outer o
WHERE EXISTS (
SELECT
FROM [compare].t_smallinner s
WHERE s.val2 - o.val2 =
)

因为查询条件压根就无法匹配导致哈希表都不会有,结果查询引擎会使用Nested Loops(Left Semi Join)来进行全表扫描,此时耗费时间接近需要2秒。好了,到这里为止我们关于IN VS EXISTS VS JOIN的分析就已经完全结束,参考资料:【https://explainextended.com/2009/06/16/in-vs-join-vs-exists/】下面我们和前面一样来对这三者下一个结论:

IN VS EXISTS VS JOIN性能分析结论:在查询非索引列时,利用JOIN查询性能低下,因为利用EXISTS和IN会直接利用半联接来匹配哈希表,而JOIN需要先进行哈希聚合之后再进行完全JOIN,换句话说,EXISTS和IN只需一步操作就完成,而JOIN需要两步操作来完成,当然对于有索引的前提下,数据量巨大的话,利用JOIN其性能同样也是非常高效的。而IN和EXISTS的性能是一样的,至于为何推荐用EXISTS的原因在于基于EXISTS是三值逻辑,而IN是两值逻辑,利用EXISTS来查询比IN更加灵活,安全、保险,而且大多数情况下利用IN来查询都可以利用EXISTS来代替查询。

总结

本节我们讨论了IN VS EXISTS VS JOIN的性能比较,至此关于所有IN/NOT IN VS EXISTS/NOT EXISTS VS JOIN/LEFT JOIN..IS NULL的性能分析到此告一段落,接下来我们将会讲述Stream Aggregate VS Hash Match Aggregate,敬请期待,简短的内容,深入的理解,我们下节再会。

SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)的更多相关文章

  1. SQL Server事务、隔离级别详解(二十九)

    前言 事务一直以来是我最薄弱的环节,也是我打算重新学习SQL Server的出发点,关于SQL Server中事务将分为几节来进行阐述,Always to review the basics. 事务简 ...

  2. SQL Server-聚焦EXISTS AND IN性能分析(十六)

    前言 前面我们学习了NOT EXISTS和NOT IN的比较,当然少不了EXISTS和IN的比较,所以本节我们来学习EXISTS和IN的比较,简短的内容,深入的理解,Always to review ...

  3. sql server 子查询 和exists使用

    概述 子查询的概念: 当一个查询是另一个查询的条件时,称之为子查询.子查询可以嵌套在主查询中所有位置,包括SELECT.FROM.WHERE.GROUP BY.HAVING.ORDER BY. 外面的 ...

  4. SQL Server中修改“用户自定义表类型”问题的分析与方法

    前言 SQL Server开发过程中,为了传入数据集类型的变量(比如接受C#中的DataTable类型变量),需要定义"用户自定义表类型",通过"用户自定义表类型&quo ...

  5. SQL SERVER 2012 执行计划走嵌套循环导致性能问题的案例

    开发人员遇到一个及其诡异的的SQL性能问题,这段完整SQL语句如下所示: declare @UserId             INT declare @PSANo              VAR ...

  6. [翻译]——SQL Server使用链接服务器的5个性能杀手

    前言: 本文是对博客http://www.dbnewsfeed.com/2012/09/08/5-performance-killers-when-working-with-linked-server ...

  7. 智能SQL优化工具--SQL Optimizer for SQL Server(帮助提升数据库应用程序性能,最大程度地自动优化你的SQL语句 )

    SQL Optimizer for SQL Server 帮助提升数据库应用程序性能,最大程度地自动优化你的SQL语句 SQL Optimizer for SQL Server 让 SQL Serve ...

  8. SQL Server ->> 尝试优化ETL中优化Merge性能

    这几天突发想到在ETL中Merge性能的问题.思路的出发点是Merge到目标表需要扫描的数据太多,而现实情况下,假设应该是只有一小部分会被更新,而且这部分数据也应该是比较新的数据,比方说对于想Fact ...

  9. (转)SQL Server上的一个奇怪的Deadlock及其分析方法

    原文地址:http://blogs.msdn.com/b/apgcdsd/archive/2012/02/28/sql-server-deadlock.aspx 最近遇到了一个看上去很奇怪,分析起来很 ...

随机推荐

  1. Unity3d学习 制作地形

    这周学习了如何在unity中制作地形,就是在一个Terrain的对象上盖几座小山,在山底种几棵树,那就讲一下如何完成上述内容. 1.在新键得项目的游戏的Hierarchy目录中新键一个Terrain对 ...

  2. 深入理解JS 执行细节

    javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链等 ...

  3. 【腾讯bugly干货分享】HTML 5 视频直播一站式扫盲

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1277 视频直 ...

  4. DDD CQRS架构和传统架构的优缺点比较

    明天就是大年三十了,今天在家有空,想集中整理一下CQRS架构的特点以及相比传统架构的优缺点分析.先提前祝大家猴年新春快乐.万事如意.身体健康! 最近几年,在DDD的领域,我们经常会看到CQRS架构的概 ...

  5. 随手记_C#验证码

    前言 最近在网上偶然看见一个验证码,觉得很有意思,于是搜了下,是使用第三方实现的,先看效果: 总体来说效果还是可以的,官方提供的SDK也比较详细,可配置性很高.在这里在简单啰嗦几句使用方式: 使用步骤 ...

  6. JavaScript之链式结构序列化

    一.概述 在JavaScript中,链式模式代码,太多太多,如下: if_else: if(...){ //TODO }else if(...){ //TODO }else{ //TODO } swi ...

  7. DataTable 转换成 Json的3种方法

    在web开发中,我们可能会有这样的需求,为了便于前台的JS的处理,我们需要将查询出的数据源格式比如:List<T>.DataTable转换为Json格式.特别在使用Extjs框架的时候,A ...

  8. 【基于WinForm+Access局域网共享数据库的项目总结】之篇一:WinForm开发总体概述与技术实现

    篇一:WinForm开发总体概述与技术实现 篇二:WinForm开发扇形图统计和Excel数据导出 篇三:Access远程连接数据库和窗体打包部署 [小记]:最近基于WinForm+Access数据库 ...

  9. 【算法】C语言实现数组的动态分配

    C语言实现数组的动态分配 作者:白宁超 2016年10月27日20:13:13 摘要:数据结构和算法对于编程的意义不言而喻,具有指导意义的.无论从事算法优化方向研究,还是大数据处理,亦或者网站开发AP ...

  10. 深入理解CSS六种颜色模式

    前面的话 赏心悦目的颜色搭配让人感到舒服,修改元素颜色的功能让人趋之若鹜.但颜色规划不当,会让网站用户无所适从.颜色从<font color="">发展至今,保留了很多 ...