SQL Server-聚焦EXISTS AND IN性能分析(十六)
前言
前面我们学习了NOT EXISTS和NOT IN的比较,当然少不了EXISTS和IN的比较,所以本节我们来学习EXISTS和IN的比较,简短的内容,深入的理解,Always to review the basics。
初步探讨EXISTS和IN
我们创建表Table1并且取出前面创建BigTable表中的六条数据并插入其中,同时有一条数据重复,如下:
CREATE TABLE Table1 (IntCol UNIQUEIDENTIFIER)
Insert into Table1 (IntCol) Values ('b927ded5-c78b-4f53-80bf-f65a6ce86d87')
Insert into Table1 (IntCol) Values ('1be326ec-4b62-4feb-8421-d9edf2df28c8')
Insert into Table1 (IntCol) Values ('91c92337-24ba-4ebf-b2a3-14b987179ca6')
Insert into Table1 (IntCol) Values ('c03168f8-c1c7-4903-a8ee-9b4d9c0b6b1f')
Insert into Table1 (IntCol) Values ('c15ac08c-8d3d-4381-9c64-54854ddf15b7')
Insert into Table1 (IntCol) Values ('c15ac08c-8d3d-4381-9c64-54854ddf15b7')
此时我们来进行IN查询
USE TSQL2012
GO SELECT SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT IntCol FROM dbo.Table1)

我们在之前讲过若是内部联接中此时会返回六条数据,因为内部联接着重强调的是JOIN后面的表,若右表有多条数据匹配上,此时则会返回多条数据,但是在IN查询中,此时只会返回五条数据,为何如此呢?

此时用IN查询时即使在子查询中有重复数据时也不会担心出问题,它会自动进行过滤处理,因为在上图中利用了Semi Join半联接中右半联接或左半联接,也就是说只返回重复的数据中的一条。那么在EXISTS中情况又是怎样呢?
SELECT SomeColumn
FROM dbo.BigTable
WHERE EXISTS (SELECT IntCol FROM dbo.Table1)
此时因为没有WHERE条件,此时会返回外部查询表中所有数据,为了和上述IN查询实现等同的结果,我们需要加上WHERE条件
USE TSQL2012
GO SELECT SomeColumn
FROM dbo.BigTable AS bt
WHERE EXISTS (SELECT IntCol FROM dbo.Table1 AS t WHERE bt.SomeColumn = t.IntCol)
而EXISTS相对于IN来说当需要比较两个或两个以上条件时,EXISTS能更好的实现而IN就没那么容易了,比如如下
SELECT SomeColumn
FROM dbo.BigTable AS bt
WHERE EXISTS (SELECT IntCol FROM dbo.Table1 AS t WHERE bt.SomeColumn = t.IntCol AND bt.OtherCol = t.OtherCol)
好了,到了这里我们开始讲讲二者性能问题
进一步探讨EXISTS和IN
我们直接利用前面的表来进行查询
SELECT ID, SomeColumn FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM SmallerTable) SELECT ID, SomeColumn FROM BigTable
WHERE EXISTS (SELECT LookupColumn FROM SmallerTable WHERE SmallerTable.LookupColumn = BigTable.SomeColumn)

二者都是利用默认的聚集索引扫描和哈希匹配中的右半联接且开销一致。接下来我们再来在二者查询列上创建索引
CREATE INDEX idx_BigTable_SomeColumn
ON BigTable (SomeColumn)
CREATE INDEX idx_SmallerTable_LookupColumn
ON SmallerTable (LookupColumn)

此时只是创建了索引后查询效率改善了,而且查询计划较之前只是哈希匹配中的左半联接替换成了合并联接中的内部联接,同时增加了流聚合。二者在开销上仍是一致的。在我所看其他教程中印象中一直都在说利用EXISTS代替IN,其EXISTS查询性能高于IN,而且事实却是开销一致,难道是100万数据太小,还是场景不够,还是语句不够复杂么。都在说看使用场景,那么到底是在什么场景下EXISTS比IN性能好呢,对此有更深入了解的你们,希望在评论中得到最实际的回答。而我认为觉得用EXISTS的话,只是EXISTS比IN更加灵活而已,而且不会出现意外的结果。下面我们继续往下看。
深入探讨EXISTS和IN
我们接下来看看用IN会出现什么意外的情况,我们首先创建测试表,并插入数据如下:
USE TSQL2012
GO CREATE TABLE table1 (id INT, title VARCHAR(), someIntCol INT)
GO
CREATE TABLE table12 (id INT, t1Id INT, someData VARCHAR())
GO
插入测试数据
INSERT INTO table1
SELECT , 'title 1', UNION ALL
SELECT , 'title 2', UNION ALL
SELECT , 'title 3', UNION ALL
SELECT , 'title 4', UNION ALL
SELECT null, 'title 5', UNION ALL
SELECT null, 'title 6', INSERT INTO table12
SELECT , , 'data 1' UNION ALL
SELECT , , 'data 2' UNION ALL
SELECT , , 'data 3' UNION ALL
SELECT , , 'data 4' UNION ALL
SELECT , , 'data 5' UNION ALL
SELECT , , 'data 6' UNION ALL
SELECT , , 'data 7' UNION ALL
SELECT , null, 'data 8' UNION ALL
SELECT , , 'data 9' UNION ALL
SELECT , , 'data 10' UNION ALL
SELECT , , 'data 11'
table1和table2中的数据分别如下:


探讨一(IN查询导致错误结果)
我们来对比EXISTS和IN查询,如下:
USE TSQL2012
GO SELECT t1.*
FROM dbo.table1 AS t1
WHERE t1.id IN (SELECT t1id FROM dbo.table12) SELECT t1.*
FROM dbo.table1 AS t1
WHERE exists (SELECT * FROM dbo.table12 AS t2 WHERE t1.id = t2.t1id)

此时二者返回的结果都是正确,接下来我们再来看其他情况,我们需要获取所有table1中数据没有在table2中的所有行。
USE TSQL2012
GO SELECT t1.*
FROM dbo.table1 AS t1
WHERE NOT EXISTS (SELECT * FROM dbo.table12 AS t2 WHERE t1.id = t2.t1id) SELECT t1.*
FROM dbo.table1 as t1
WHERE t1.id NOT IN (SELECT t1id FROM dbo.table12 as t2)

此时利用EXISTS得到了正确的结果,而通过IN查询未达到我们查询的目的,原因之前也有说过IN是基于三值逻辑,此时遇到NULL则会当做UNKNOWN来处理,所以最终得到的结果集是错误的。我们继续往下探讨。
探讨2(手写错误导致意外结果)
我们重新创建测试表并插入测试数据,如下:
USE TSQL2012
GO CREATE TABLE TestTable1 (id1 int)
CREATE TABLE TestTable2 (id2 int) INSERT TestTable1 VALUES(),(),()
INSERT TestTable2 VALUES(),()
我们首先进行如下查询:
USE TSQL2012
GO SELECT *
FROM TestTable1
WHERE id1 IN (SELECT id2 FROM TestTable2)

此时结果是正确的,假如在子查询中我们将列id2写成了id1,那么情况又会是怎样的呢?
SELECT *
FROM TestTable1
WHERE id1 IN (SELECT id1 FROM TestTable2)

不知你是否注意到什么没有,表面是没什么问题,我们接着运行下上述子查询
SELECT id1 FROM TestTable2

单独运行查询时,结果居然出错了,到这了我们再看下创建的表的列,id1是在Table1中而非在Table2中,所以导致了这种意外的错误,如果手写错误,结果数据也有,一般是不会觉察不到,通过使用IN查询就导致了意外的出现。而如下利用EXISTS时会直接报错,而不是得到错误的结果集
SELECT *
FROM t1
WHERE EXISTS (SELECT * FROM TestTable2 t2 WHERE t2.id2 = t1.id1 )
当然了也有人会说根本不会犯这样低级错误,但是谁能保证呢,SQL有智能提示更加容易犯这样的错误,因为直接在子查询就会有这样的列出现,但是该列在子查询表中根本不存在。所以基于探讨的两点,利用EXISTS更加保险。到此,关于EXISTS和IN的介绍算是结束,下此结论。
EXISTS和IN性能分析结论:我们推荐使用EXISTS,而不是IN,原因不是EXISTS性能优于IN,二者性能开销是一样的,而是利用EXISTS比IN更加灵活,更加安全、保险不会出现意想不到的结果。
总结
本节我们讲解了EXISTS和IN,关于其二者在性能方面还是有点疑惑,毕竟场景不够,当然最后还是推荐使用EXISTS,而原因不在于性能。我们下节讲解LEFT JOIN和NOT EXISTS,简短的内容,深入的理解,我们下节再会。
SQL Server-聚焦EXISTS AND IN性能分析(十六)的更多相关文章
- SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)
前言 本节我们开始讲讲这一系列性能比较的终极篇IN VS EXISTS VS JOIN的性能分析,前面系列有人一直在说场景不够,这里我们结合查询索引列.非索引列.查询小表.查询大表来综合分析,简短的内 ...
- 十、SQL中EXISTS的用法 十三、sql server not exists
十.SQL中EXISTS的用法 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False EXISTS 指定一个子查询,检测 行 的存在. 语法 ...
- SQL Server管理员必备技能之性能优化
SQL Server管理员必备技能之性能优化 高文龙关注1人评论1171人阅读2017-09-22 08:27:41 SQL Server 作为企业必不可少的服务之一,所以对于管理员的日常运维是一个极 ...
- SQL Server一个特殊的阻塞案例分析2
最近发现一个非常奇怪的阻塞问题,如下截图所示(来自监控工具DPA),会话583被会话1036阻塞,而且阻塞发生在tempdb,被阻塞的SQL如下截图所示,会话等待类型为LCK_M_S 因为DPA工具不 ...
- SQL中利用DMV进行数据库性能分析
相信朋友对SQL Server性能调优相关的知识或多或少都有一些了解.虽然说现在NOSQL相关的技术非常的火热,但是RMDB(关系型数据库)与NOSQL是并存的,并且适用在各种的项目中.在一般的企业级 ...
- Sql Server 2012 的新分页方法分析(offset and fetch) - 转载
最近在分析 Sql Server 2012 中 offset and fetch 的新特性,发现 offset and fetch 无论语法的简洁还是功能的强大,都是相当相当不错的 其中 offset ...
- 使用SQL Server 2000索引视图提高性能
什么是索引视图? 许多年来,Microsoft? SQL Server? 一直都提供创建虚拟表(称为视图)的功能.在过去,这些视图主要有两种用途: 提供安全机制,将用户限制在一个或多个基表中的数据的某 ...
- SQL Server 数据库中关于死锁的分析
SQL Server数据库发生死锁时不会像Oracle那样自动生成一个跟踪文件.有时可以在[管理]->[当前活动] 里看到阻塞信息(有时SQL Server企业管理器会因为锁太多而没有响应). ...
- SQL Server里书签查找的性能伤害
在我的博客上,以前我经常谈到SQL Serverl里的书签查找,还有它们带来的很多问题.在今天的文章里,我想从性能角度进一步谈下书签查找,还有它们如何拉低你整个SQL Server性能. 书签查找—— ...
随机推荐
- 使用HTML5开发Kinect体感游戏
一.简介 我们要做的是怎样一款游戏? 在前不久成都TGC2016展会上,我们开发了一款<火影忍者手游>的体感游戏,主要模拟手游章节<九尾袭来 >,用户化身四代,与九尾进行对决, ...
- win10 环境 gitbash 显示中文乱码问题处理
gitbash 是 windows 环境下非常好用的命令行终端,可以模拟一下linux下的命令如ls / mkdir 等等,如果使用过程中遇到中文显示不完整或乱码的情况,多半是因为编码问题导致的,修改 ...
- [linux]阿里云主机的免登陆安全SSH配置与思考
公司服务器使用的第三方云端服务,即阿里云,而本地需要经常去登录到服务器做相应的配置工作,鉴于此,每次登录都要使用密码是比较烦躁的,本着极速思想,我们需要配置我们的免登陆. 一 理论概述 SSH介绍 S ...
- MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信
MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...
- 重撸js_2_基础dom操作
1.node 方法 返回 含义 nodeName String 获取节点名称 nodeType Number 获取节点类型 nodeValue String 节点的值(注意:文本也是节点) 2.inn ...
- 【需求设计1】VIP积分系统无聊YY
RT,想到什么就写什么呗,这是最简单的方式,顺便给自己做一个记录,反正自己记忆力也不太好.本文是仿陆金所的积分系统,自己YY的一套东西. 首先我想做一个VIP兑换投资卷的功能: 我们先来确定一些我知道 ...
- 海康网络摄像机YV12转换为BGR,由opencv Mat显示 (转)
我使用的是海康DS-2CD852MF-E, 200万,网络摄像机,已经比较老了,不过SDK在海康官网下载的,开发流程都差不多. 海康摄像机回调解码后的视频数据格式为YV12,顺便说一下YV12的数据格 ...
- 【JQ基础】数组
each() 方法规定为每个匹配元素规定运行的函数.
- css 填坑常用代码分享
以下是常用的代码收集,没有任何技术含量,只是填坑的积累.转载请注明出处,谢谢. 因为提交比较麻烦,后来转置github:https://github.com/jsfront/src/blob/mast ...
- MVVM大比拼之knockout.js源码精析
简介 本文主要对源码和内部机制做较深如的分析,基础部分请参阅官网文档. knockout.js (以下简称 ko )是最早将 MVVM 引入到前端的重要功臣之一.目前版本已更新到 3 .相比同类主要有 ...