关于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去“优化”了。

时间: 2024-10-30 23:35:44

关于T-SQL中exists或者not exists子查询的“伪优化”的做法的相关文章

SQL 子查询,索引优化

场景 索引优化 单列索引 多列索引 索引覆盖 排序 场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表 create table Course( c_id int PRIMARY KEY, name varchar(10) ) 数据100条 学生表: create table Student( id int PRIMARY KEY, name varchar(10) ) 数据70000条 学生成绩表SC CREATE table SC( sc_id int PRIMARY KEY

SQL SERVER技术内幕之4 子查询

最外层查询的结果集会返回给调用者,称为外部查询.内部查询的结果是供外部查询使用的,也称为子查询.子查询可以分成独立子查询和相关子查询两类.独立子查询不依赖于它所属的外部查询,而相关子查询则须依赖它所属的外部查询.子查询的期望值可以是单值的.多值的或以表为值. 1.独立子查询 独立子查询是独立于其外部查询的子查询.在逻辑上,独立子查询在执行外部查询之前只要先执行一次,接着外部查询再使用子查询的结果继续进行查询. 1.1 独立标量子查询 标量子查询是返回单个值的子查询,标量子查询可以出现在外部查询中

SQL主、外键,子查询

主键 数据库主键是指表中一个列或列的组合,其值能唯一地标识表中的每一行.这样的一列或多列称为表的主键,通过它可强制表的实体完整性.当创建或更改表时可通过定义 PRIMARY KEY约束来创建主键.一个表只能有一个 PRIMARY KEY 约束,而且 PRIMARY KEY 约束中的列不能接受空值.由于 PRIMARY KEY 约束确保唯一数据,所以经常用来定义标识列. 主键的作用 主键的主要作用如下: (1)保证实体的完整性: (2)加快数据库的操作速度: (3) 在表中添加新记录时,数据库会自

sql语句增删改查与子查询

修改表 修改表 语法: Alter table <旧表名> rename [ TO] <新表名>; 例子:Alter table `demo01` rename `demo02`; 添加字段 语法: Alter Table 表名 ADD 字段名  数据类型  [属性]; 例子:Alter Table `Demo02` ADD `passWord`  varchar(50) not null; 修改字段 语法: Alter table 表名 change  原字段名  新字段名  数

ORACLE查询当前资产状态,和另一个数据库联查,(查询重复数据中第一条),子查询作为字段查询

背景:ORACLE查询当前资产状态,包含资产信息(表1),资产维修状态(表2),资产报废状态(表3) 如下: 资产信息: 资产维修: 资产报废: 资产申请完了以后可以申请当前资产的维修和报废,其中维修有两个流程,一个是申请维修,然后维修.对应的都需要启动相应的流程去申请维修或者报废 流程表如下: 查询当前所有的资产以及对应的资产状态(维修状态,报废状态):sql语句如下: select t.ASSET_ID             as assetId,       t.ASSET_NAME  

关于Hive中case when不准使用子查询的解决方法

在公司用Hive实现个规则的时候,遇到了要查询某个字段是否在另一张表中,大概情况就是 A表: id value1 value2 1 100 0 2 101 1 3 102 1 B表: value1 100 102 104 我要查询A表中当value2为0的时候直接输出0,为1的时候,判断value1是否在B表的value1中,如果在那么便输出0,不在便输出1,拿到第一反映是: select case when value2 = 0 then 0 when value2 = 1 then case

SQL语句面试题目:一般查询和高级子查询

几个表 employees 表: EMPLOYEE_ID              NUMBER(6) FIRST_NAME                VARCHAR2(20) LAST_NAME                 VARCHAR2(25) EMAIL                               VARCHAR2(25) PHONE_NUMBER       VARCHAR2(20) HIRE_DATE                  DATE JOB_ID 

关系数据库SQL之基本数据查询:子查询、分组查询、模糊查询

http://www.jianshu.com/p/eeb6a898d4ec 前言 上一篇关系数据库常用SQL语句语法大全主要是关系型数据库大体结构,本文细说一下关系型数据库查询的SQL语法. SQL数据查询 语法回顾 SELECT [ALL|DISTINCT] <目标列表达式>[,<目标列表达式>]- FROM <表名或视图名>[,<表名或视图名>]- [WHERE <条件表达式>] [GROUP BY <列名> [HAVING &l

sql中 in 、not in 、exists、not exists 用法和差别

exists (sql 返回结果集为真) not exists (sql 不返回结果集为真) 如下: 表A ID NAME 1    A1 2    A2 3  A3 表B ID AID NAME 1    1 B1 2    2 B2 3    2 B3 表A和表B是1对多的关系 A.ID => B.AID SELECT ID,NAME FROM A WHERE EXIST (SELECT * FROM B WHERE A.ID=B.AID) 执行结果为 1 A1 2 A2 原因可以按照如下分