关于T-SQL中exists或者not exists子查询的“伪优化”的做法
问题起源
在使用t-sql中的exists(或者not exists)子查询的时候,不知道什么时候开始,发现一小部分人存在一种“伪优化”的一些做法,
并且向不明真相的群众传递这一种写法“优越性”,实在看不下去,
无法传递给他人正确的指导思想无可厚非,给他人传递错误的思想或者说误导人倒是一种罪恶。
本来这个事情是不值得一提的,看到越来越多被误导的群众开始推崇这种做法(甚至开始坚信了),实在是看不习惯,不吐不快。
典型的问题如下
select * from TableA a
where exists
(select 1 from TableB b where a.Id = b.Id ),当然这里子查询里写成select * 也无所谓。
这个要表达的逻辑就是说B表中存在与A表相同的Id的数据,就成立,这是要表达的逻辑。
参考如下写法,有人偏偏在在exists子查询中加上top 1 1,问其原因,为什么提高性能?理由就是加了top 1 1,只要在TableB中存在一条满足条件的条件即可,同时不用返回所有的行和列,因此可以提高性能。
select * from TableA a
where exists
(select top 1 1 from TableB b where a.Id = b.Id )
与直接写select 1 from TableB where a.Id =b.Id相比,真的可以提高性能吗?
exists(或者not exists)子查询的实现是一种半连接的“探测”逻辑机制(Semi Join),意思就是只要存在(而不关心具体有多少条)符合条件的数据即可,当然是不会再B表中找到所有的数据行(或者列)之后再返回。
但是exists(或者not exists)具体在执行的时候,到底走不走Semi Join不一定,跟具体的执行计划有关,本文暂不讨论走不走Semi Join的问题,只讨论子查询中select top 1 1 的写法到底影不影响效率。
测试验证
就以AdventureWorks2012示例库的两个表做demo,看看两者的执行计划和IO信息,会发现子查询中加不加 top 1,执行计划一样,IO一样,扯什么性能……
exists(或者not exists)的半连接的逻辑机制(Semi Join)决定了,你写不写top 1,它都是找到一个符合条件的数据之后就返回外层查询,
甚至在子查询中写select * from TableName,如果走Semi Join的执行方式,他照样是探测到有一条存在的数据之后就返回,肯定不会把所有的行都给找出来再返回,
以下截图可以看到,即便子查询是select * ,IO信息也是一样的(当然执行计划也一样)。
在当前这种情况下,可以认为exists子查询中的*,也是不会影响效率什么的。
甚至是可以在子查询中select一个常量,也不会影响到效率或者说改变执行计划。
总结
这个问题比较简答,当然这个场景也仅限于sqlserver中的exists或者not exists子查询,对于别的数据库也不确定是不是优化器内部会自动优化。
当前这种场景下,对于sqlserver来说,不要费尽心思去刻意用select top 1 1去“优化”了。
关于T-SQL中exists或者not exists子查询的“伪优化”的做法的更多相关文章
- SQL中IN,NOT IN,EXISTS,NOT EXISTS的用法和差别
SQL中IN,NOT IN,EXISTS,NOT EXISTS的用法和差别: IN:确定给定的值是否与子查询或列表中的值相匹配. IN 关键字使您得以选择与列表中的任意一个值匹配的行. 当要获得居住在 ...
- 在论坛中出现的比较难的sql问题:4(row_number函数+子查询 分组连续编号问题)
原文:在论坛中出现的比较难的sql问题:4(row_number函数+子查询 分组连续编号问题) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路. 求一查询语句 http: ...
- 在论坛中出现的比较难的sql问题:32(row_number函数+子查询 sql循环取差值)
原文:在论坛中出现的比较难的sql问题:32(row_number函数+子查询 sql循环取差值) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路. sql循环取差值,该怎 ...
- 在论坛中出现的比较难的sql问题:31(row_number函数+子查询 月环比计算)
原文:在论坛中出现的比较难的sql问题:31(row_number函数+子查询 月环比计算) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.
- 在论坛中出现的比较难的sql问题:2(row_number函数+子查询)
原文:在论坛中出现的比较难的sql问题:2(row_number函数+子查询) 2.如何去掉字段内的重复.
- 数据库常用SQL语句(三):子查询
一.为什么会使用子查询 虽然可以通过连接查询来实现多表查询数据记录,但不建议使用,因为连接查询的性能很差,为什么呢?我们来进行分析,例如 我们要查询部门表t_dept 和雇员表t_employee中的 ...
- 为什么sql里面not in后面的子查询如果有记录为NULL的,主查询就查不到记录
为什么sql里面not in后面的子查询如果有记录为NULL的,主查询就查不到记录???原因很简单: SELECT * FROM dbo.TableA AS a WHERE a.id NOT IN ( ...
- sql中 in , not in , exists , not exists效率分析
in和exists执行时,in是先执行子查询中的查询,然后再执行主查询.而exists查询它是先执行主查询,即外层表的查询,然后再执行子查询. exists 和 in 在执行时效率单从执行时间来说差不 ...
- SQL Server进阶(五)子查询
概述 子查询的概念: 当一个查询是另一个查询的条件时,称之为子查询.子查询可以嵌套在主查询中所有位置,包括SELECT.FROM.WHERE.GROUP BY.HAVING.ORDER BY. 外面的 ...
随机推荐
- (转)开源OpenWRT知识
原博地址:http://www.thinkingquest.net/article/466 我们都需要使用google提供的搜索,gmail等优质服务.但是由于方墙的存在,使得大家各自搞各自的FQ办法 ...
- js基本方法
Math.random() 日期时间函数(需要用变量调用):var b = new Date(); //获取当前时间b.getTime() //获取时间戳b.getFullYear() //获取年份b ...
- IDEA Git 配置及使用
1.下载并安装 Git 2.新建项目 3.配置版本控制器 4.新建github仓库 5.定位到项目根目录,执行命令 创建git仓库时忘记添加 .gitignore 怎么办? vi .gitignore ...
- Javascript异步编程的4种方法(阮一峰)
转载: http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html 你可能知道,Javascript语言的执 ...
- day18包的使用与日志(logging)模块
包的使用与日志(logging)模块1. 什么是包 包就是一个包含有__init__.py文件的文件夹 包本质就是一种模块,即包是用包导入使用的,包内部包含的文件也都是用来被导入使用2 为 ...
- mac OS 安装maven遇到问题e45: 'readonly' option is set
1.下载 Maven, 并解压到某个目录.例如/Users/yintingting/apache-maven-3.3.9 2.打开Terminal,输入以下命令,设置Maven classpath v ...
- linux 查看磁盘空间
linux 查看磁盘空间大小命令 df :命令是linux系统以磁盘分区为单位查看文件系统,可以加上参数查看磁盘剩余空间信息 df -hl:查看磁盘剩余空间信息,显示如下: 文件系统 ...
- Linux的JDK配置
1.下载jdk-7u1-linux-i586.rpm2.cd 到 jdk-7u1-linux-i586.rpm 所在的目录3.su 获得 root 权限4.执行安装命令: rpm -ivh jdk-7 ...
- ajax 406 Not Acceptable
搞了半天, 后面参照 http://www.th7.cn/web/ajax/201611/194702.shtml, 终于把问题解决了.. 使用ajax向后台请求时,前台报错406 Not Accep ...
- beeline 连接hive
HiveServer2是一个能使客户端针对hive执行查询的一种服务,与HiverServer1比较,它能够支持多个客户端的并发请求和授权的:HiveCLI 和 hive –e的方式比较单一,HS2允 ...