关于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. 外面的 ...
随机推荐
- keras的LSTM函数详解
keras.layers.recurrent.LSTM(units, activation='tanh', recurrent_activation='hard_sigmoid', use_bias= ...
- windows服务没有及时响应启动或控制请求
单击开始,单击运行,键入regedit,然后单击“确定”. 找到并单击以下注册表子项:HKEY_LOCAL_MACHINE——SYSTEM——CurrentControlSet——Control 在右 ...
- Android---页面跳转
1.首先在一个布局文件(.XML)中绘画了一个跳转按钮(id为btn1): <Button android:id="@+id/btn1" an ...
- HBase的Shell命令和JavaAPI
HBase的shell操作和JavaAPI的使用: Shell 表操作 创建表 create 'student','info' #表名 列族 插入表 put 'student','1001','inf ...
- Best Practice AngularJS
Best Practice AngularJS /* 用几组简明扼要的代码段及其说明, 展示良好的编程行为, angularjs */ // app.module.js angular .module ...
- JavaScript常见的创建对象的几种方式
1.通过Object构造函数或对象字面量创建单个对象 这些方式有明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码.为了解决这个问题,出现了工厂模式. 2.工厂模式 考虑在ES中无法创建类( ...
- 关于elment-ui树形控件Tree的使用
如果简单使用的tree树形控件,按照Element ui Tree 树形控件 官方文档使用即可,基本上能够完成大部分的需求. 但是如果需要对树形结构进行额外操作,仅仅根据官方文档提供的方案的话,可能就 ...
- SQL Server 合并行
select a.*,b.Organization_Name,c.User_Name sgry,c.renNum,d.User_Name fzr,e.pic_url from dbo.TB_ZYM_L ...
- 启动tomcat时cmd窗口一闪而过
在tomcat的安装目录下 双击startup.bat启动时cmd窗口一闪而过 1.在系统中查看配置JDK的环境变量是否正确 2.进入tomcat的安装目录 在启动tomcat时流程是:startup ...
- 错误代码: 1231 - Variable 'sql_mode' can't be set to the value of 'NULL'
错误代码: 1231 - Variable 'sql_mode' can't be set to the value of 'NULL' 错误代码: - Variable 'sql_mode' can ...