SQL语句中exits和in的区别

article/2025/10/31 2:49:47

一 表展示

查询中涉及到的两个表,一个user和一个order表,具体表的内容如下:

user表:

order表:

二 in 演示

确定给定的值是否与子查询或列表中的值相匹配。in在查询的时候,首先查询子查询的表,然后将内表和外表做一个笛卡尔积,然后按照条件进行筛选。所以相对内表比较小的时候,in的速度较快。

具体sql语句如下:

SELECT*FROM`user`WHERE`user`.id IN (SELECT`order`.user_idFROM`order`)

这条语句很简单,通过子查询查到的user_id 的数据,去匹配user表中的id然后得到结果。该语句执行结果如下:

它的执行流程是什么样子的呢?让我们一起来看一下。

首先,在数据库内部,查询子查询,执行如下代码:

SELECT`order`.user_idFROM`order`

执行完毕后,得到结果如下:

此时,将查询到的结果和原有的user表做一个笛卡尔积,结果如下:

此时,再根据我们的user.id IN order.user_id的条件,将结果进行筛选(既比较id列和user_id 列的值是否相等,将不相等的删除)。最后,得到两条符合条件的数据。

select * from A where id in(select id from B)

以上查询使用了in语句,in()只执行一次,它查出B表中的所有id字段并缓存起来.之后,检查A表的id是否与B表中的id相等,如果相等则将A表的记录加入结果集中,直到遍历完A表的所有记录. 它的查询过程类似于以下过程

List resultSet=[]; Array A=(select * from A); Array B=(select id from B);
for(int i=0;i<A.length;i++) { for(int j=0;j<B.length;j++) { if(A[i].id==B[j].id) { resultSet.add(A[i]); break; } } } return resultSet;

可以看出,当B表数据较大时不适合使用in(),因为它会B表数据全部遍历一次. 如:A表有10000条记录,B表有1000000条记录,那么最多有可能遍历10000*1000000次,效率很差. 再如:A表有10000条记录,B表有100条记录,那么最多有可能遍历10000*100次,遍历次数大大减少,效率大大提升.

结论:in()适合B表比A表数据小的情况

三 exists 演示

指定一个子查询,检测行的存在。遍历循环外表,然后看外表中的记录有没有和内表的数据一样的。匹配上就将结果放入结果集中。

具体sql语句如下:

SELECT`user`.*FROM`user`WHEREEXISTS (SELECT`order`.user_idFROM`order`WHERE`user`.id = `order`.user_id)

这条sql语句的执行结果和上面的in的执行结果是一样的。

但是,不一样的是它们的执行流程完全不一样:

使用exists关键字进行查询的时候,首先,我们先查询的不是子查询的内容,而是查我们的主查询的表,也就是说,我们先执行的sql语句是:

SELECT `user`.* FROM `user`

得到的结果如下:

然后,根据表的每一条记录,执行以下语句,依次去判断where后面的条件是否成立:

EXISTS (SELECT`order`.user_idFROM`order`WHERE`user`.id = `order`.user_id)

如果成立则返回true不成立则返回false。如果返回的是true的话,则该行结果保留,如果返回的是false的话,则删除该行,最后将得到的结果返回。

select a.* from A a where exists(select 1 from B b where a.id=b.id)

以上查询使用了exists语句,exists()会执行A.length次,它并不缓存exists()结果集,因为exists()结果集的内容并不重要,重要的是结果集中是否有记录,如果有则返回true,没有则返回false. 它的查询过程类似于以下过程

List resultSet=[]; Array A=(select * from A)
for(int i=0;i<A.length;i++) { if(exists(A[i].id) {

//执行select 1 from B b where b.id=a.id是否有记录返回

resultSet.add(A[i]); } } return resultSet;

当B表比A表数据大时适合使用exists(),因为它没有那么遍历操作,只需要再执行一次查询就行. 如:A表有10000条记录,B表有1000000条记录,那么exists()会执行10000次去判断A表中的id是否与B表中的id相等. 如:A表有10000条记录,B表有100000000条记录,那么exists()还是执行10000次,因为它只执行A.length次,可见B表数据越多,越适合exists()发挥效果. 再如:A表有10000条记录,B表有100条记录,那么exists()还是执行10000次,还不如使用in()遍历10000*100次,因为in()是在内存里遍历比较,而exists()需要查询数据库,我们都知道查询数据库所消耗的性能更高,而内存比较很快.

结论:exists()适合B表比A表数据大的情况

当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用.

三 区别及应用场景

in 和 exists的区别: 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。其实我们区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询,所以我们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 ,另外IN时不对NULL进行处理

in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。一直以来认为exists比in效率高的说法是不准确的。

等价语句:

SELECT /*+ PARALLEL*/ 'HL',T1.*,SYSDATE,'2017-05' FROM  DC_ALL_HL.V_OFFER_INST_INFO T1
WHERE T1.PROD_INST_ID IN ( SELECT PROD_INST_ID FROM AUDI_SAMPLE_HL);SELECT /*+ PARALLEL(T1,50)*/ 'HL',T1.*,SYSDATE,'2017-05' FROM  DC_ALL_HL.V_OFFER_INST_INFO T1<br>WHERE  EXISTS (<br>          SELECT * FROM AUDI_SAMPLE_HL AU where T1.PROD_INST_ID = AU.PROD_INST_ID);

四 not in 和not exists

如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。

比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID FROM Orders o WHERE o.CustomerID=c.CustomerID) 这里面的EXISTS是如何运作呢?子查询返回的是OrderId字段,可是外面的查询要找的是CustomerID和CompanyName字段,这两个字段肯定不在OrderID里面啊,这是如何匹配的呢?
EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或 False EXISTS 指定一个子查询,检测 行 的存在。
语法: EXISTS subquery 参数: subquery 是一个受限的 SELECT 语句 (不允许有 COMPUTE 子句和 INTO 关键字)。 结果类型: Boolean 如果子查询包含行,则返回 TRUE ,否则返回 FLASE 。

例表A:TableIn 例表B:TableEx

a). 在子查询中使用 NULL 仍然返回结果集 select * from TableIn where exists(select null) 等同于: select * from TableIn

b). 比较使用 EXISTS 和 IN 的查询。注意两个查询返回相同的结果。

select * from TableIn where exists(select BID from TableEx where BNAME=TableIn.ANAME)

select * from TableIn where ANAME in(select BNAME from TableEx)

c). 比较使用 EXISTS 和 = ANY 的查询。注意两个查询返回相同的结果。

select * from TableIn where exists(select BID from TableEx where BNAME=TableIn.ANAME)

select * from TableIn where ANAME=ANY(select BNAME from TableEx)

NOT EXISTS 的作用与 EXISTS 正好相反。如果子查询没有返回行,则满足了 NOT EXISTS 中的 WHERE 子句。

结论: EXISTS(包括 NOT EXISTS )子句的返回值是一个BOOL值。 EXISTS内部有一个子查询语句(SELECT ... FROM...), 我将其称为EXIST的内查询语句。其内查询语句返回一个结果集。 EXISTS子句根据其内查询语句的结果集空或者非空,返回一个布尔值。

一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果取非空值,则EXISTS子句返回TRUE,这一行行可作为外查询的结果行,否则不能作为结果。

分析器会先看语句的第一个词,当它发现第一个词是SELECT关键字的时候,它会跳到FROM关键字,然后通过FROM关键字找到表名并把表装入内存。接着是找WHERE关键字,如果找不到则返回到SELECT找字段解析,如果找到WHERE,则分析其中的条件,完成后再回到SELECT分析字段。最后形成一张我们要的虚表。 WHERE关键字后面的是条件表达式。条件表达式计算完成后,会有一个返回值,即非0或0,非0即为真(true),0即为假(false)。同理WHERE后面的条件也有一个返回值,真或假,来确定接下来执不执行SELECT。 分析器先找到关键字SELECT,然后跳到FROM关键字将STUDENT表导入内存,并通过指针找到第一条记录,接着找到WHERE关键字计算它的条件表达式,如果为真那么把这条记录装到一个虚表当中,指针再指向下一条记录。如果为假那么指针直接指向下一条记录,而不进行其它操作。一直检索完整个表,并把检索出来的虚拟表返回给用户。EXISTS是条件表达式的一部分,它也有一个返回值(true或false)。
在插入记录前,需要检查这条记录是否已经存在,只有当记录不存在时才执行插入操作,可以通过使用 EXISTS 条件句防止插入重复记录。 INSERT INTO TableIn (ANAME,ASEX) SELECT top 1 '张三', '男' FROM TableIn WHERE not exists (select * from TableIn where TableIn.AID = 7)
EXISTS与IN的使用效率的问题,通常情况下采用exists要比in效率高,因为IN不走索引,但要看实际情况具体使用: IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。


http://chatgpt.dhexx.cn/article/i7iuuTcA.shtml

相关文章

E. Exits in Excess

题意&#xff1a; 移除最多一半的边使得图没有环。 将所有边分成两部分&#xff0c; 第一部分为 u < v u < v u<v&#xff0c; 第二部分为 v > u v > u v>u&#xff0c; 将小的边集合删去即可。 AC代码&#xff1a; int n, m; vector<int> v1, v2…

20220621 Dual Quaternion

文章目录 对偶数一、对偶数是什么&#xff1f;二、对偶矢量三、对偶四元数 对偶数 一、对偶数是什么&#xff1f; https://zhuanlan.zhihu.com/p/358146509 对偶数是一种特殊的自洽的运算&#xff0c;类似于常用的复数基本单位 i i i &#xff08; i 2 − 1 i^2-1 i2−1&a…

Quaternion

01:欧拉角 1.欧拉角Vector3(x,y,z)代表的是旋转物体&#xff08;若是标准旋转那么是旋转坐标轴x,y,z&#xff0c;转换为旋转物体则旋转角度取反顺序不变&#xff09;&#xff0c;且是将物体从物体坐标系旋转到惯性坐标系&#xff08;世界坐标系中为了渲染&#xff09;&#x…

Quaternion.Euler调整记录

Quaternion.Euler调整 1.运行unity 调整摄像头视角&#xff0c;找到需要的位置&#xff0c;记录下 摄像头的位置和旋转角度。 2.调整空物体的位置 使之位置与需要的位置一致 3.调整Quaternion.Euler 使Quaternion.Euler与旋转数值一致。

Quaternion(四元数)和旋转以及Yaw, pitch, roll 的含义

原文&#xff1a; http://www.linuxgraphics.cn/graphics/opengl_quaternion.html Quaternion(四元数)和旋转 本文介绍了四元数以及如何在OpenGL中使用四元数表示旋转。 Quaternion 的定义 四元数一般定义如下&#xff1a; qwxiyjzk其中 w,x,y,z是实数。同时&#xff0c;有…

Unity3d开发之对Quaternion的使用

上周找到了新公司。这周二来上班。可怕的是我刚去的第二天下午四点领导通知我做一个VRdemo&#xff0c;要求第二天交。我勒个擦。我现在对设备还没熟悉呢。连sdk都没下载而且距离上一次开发vr是在快两年之前了。属实让我措手不及。没错&#xff0c;按剧本走&#xff0c;加班到凌…

【Unity编程】四元数(Quaternion)与欧拉角

欧拉旋转、四元数、矩阵旋转之间的差异 除了欧拉旋转以外&#xff0c;还有两种表示旋转的方式&#xff1a;矩阵旋转和四元数旋转。接下来我们比较它们的优缺点。 欧拉角 优点&#xff1a;三个角度组成&#xff0c;直观&#xff0c;容易理解。优点&#xff1a;可以进行从一个方…

Quaternion类

Euler public static Quaternion Euler(float x, float y, float z); public static Quaternion Euler(Vector3 euler); 功能: 返回Quaternion对应的欧拉角 例子&#xff1a; public class ExampleClass : MonoBehaviour {public Quaternion rotation Quaternion.Euler(0, 30,…

Unity Quaternion

Quaternion 类的属性 eulerAngles 欧拉角 Quaternion 类的实例方法 1、SetFromToRotion 函数 2、SetLookRotation 函数 3、ToAngleAxis 函数 Quaternion 类的静态方法 1、Angle方法 2、Dot方法 3、Euler方法 4、FromToRotation方法 5、Inverse方法 6、Lerp方法 7…

【第018问 Unity中对Quaternion.AngleAxis的理解?】

一、背景 在游戏研发过程中&#xff0c;有时候会对一个物体经过多次围绕不同的轴进行不同角度的旋转&#xff0c;从而计算得到一个方向&#xff0c;以此来检测在该对应的方向上是否有对应的物体或别的对象&#xff0c;因此本节对Quaternion.AngleAxis进行简单的记录&#xff1…

Unity API详解——Quaternion类

Quaternion类又称四元数&#xff0c;由x、y、z和w这4个分量组成&#xff0c;属于struct类型。在Unity中&#xff0c;用Quaternion来存储和表示对象的旋转角度。Quaternion的变换比较复杂&#xff0c;对于GameObject一般的旋转及移动&#xff0c;可以用Transform中的相关方法实现…

Unity3D - 详解Quaternion类[转载]

一、简介 Quaternion又称四元数&#xff0c;由x,y,z和w这四个分量组成&#xff0c;是由爱尔兰数学家威廉卢云哈密顿在1843年发现的数学概念。四元数的乘法不符合交换律。从明确地角度而言&#xff0c;四元数是复数的不可交换延伸。如把四元数的集合考虑成多维实数空间的话&…

【Unity】Unity常用类:向量Vector3、四元数Quaternion

文章目录 Vector3构造函数静态变量变量运算符常用方法&#xff08;静态&#xff09;OrthoNormalize&#xff08;正交标准化&#xff09;Reflect&#xff08;反射&#xff09;Lerp&#xff08;线性插值&#xff09; Quaternion构造函数静态变量变量常用方法Eular&#xff08;欧拉…

unity学习笔记——Quaternion(四元数)

本篇文章转自https://www.cnblogs.com/driftingclouds/p/6626183.html Quaternion类 Quaternion&#xff08;四元数&#xff09;用于计算Unity旋转。它们计算紧凑高效&#xff0c;不受万向节锁的困扰&#xff0c;并且可以很方便快速地进行球面插值。 Unity内部使用四元数来表…

【Unity编程】Unity中关于四元数的API详解

Unity中关于四元数的API详解 Quaternion类 Quaternion&#xff08;四元数&#xff09;用于计算Unity旋转。它们计算紧凑高效&#xff0c;不受万向节锁的困扰&#xff0c;并且可以很方便快速地进行球面插值。 Unity内部使用四元数来表示所有的旋转。 Quaternion是基于复数&am…

四元数快速入门【Quaternion】

四元数&#xff08;Quaternion&#xff09;是用于旋转和拉伸向量的数学运算符。 本文提供了一个概述&#xff0c;以帮助理解在空间导航等应用程序中对四元数的需求。 推荐&#xff1a;用 NSDT场景设计器 快速搭建3D场景。 可以通过多种方式在空间中准确定位、移动和旋转物体。 …

四元数(Quaternion)食用指南

四元数&#xff08;Quaternion&#xff09;食用指南 “这简直就是黑魔法&#xff01;” 开发时&#xff0c;每次遇到旋转问题时总会心头一震&#xff0c;在欧拉角和四元数这两种处理方式的选择上犹豫不决&#xff0c;不知不觉就陷入了四元数的淤泥中…接下来&#xff0c;我决定…

Unity3D - 详解Quaternion类

一、简介 Quaternion又称四元数&#xff0c;由x,y,z和w这四个分量组成&#xff0c;是由爱尔兰数学家威廉卢云哈密顿在1843年发现的数学概念。四元数的乘法不符合交换律。从明确地角度而言&#xff0c;四元数是复数的不可交换延伸。如把四元数的集合考虑成多维实数空间的话&…

int 的最大值

int 的最大值 java int 类整数的最大值是 2 的 31 次方 - 1 2147483648 - 1 2147483647 可以用 Integer.MAX_VALUE 表示它&#xff0c;即 int value Integer.MAX_VALUE; Integer.MAX_VALUE 1 Integer.MIN_VALUE -2147483648 再大的数就要用 long &#xff08;最大值 …

Python获取int最大值和float最大值

计算机所能表示的最大值&#xff0c;根据你的计算机的位数决定。有机计算机是64位&#xff0c;有的是32位&#xff0c;因此具体情况各不相同。本人的电脑是64位的。 1.获得int型的最大值 import sys MAX_INTsys.maxsize print(MAX_INT)2.获得float型的最大值 ##灰常简单 max…