当前位置: 首页 > news >正文

MySQL 关键字 IN 与 EXISTS 的使用与区别

目录

  • 1. IN & NOT IN
    • 1.1 基本使用
    • 1.2 工作原理
      • 1.2.1 静态值列表的 IN 语句
      • 1.2.2 子查询的 IN 语句
    • 1.3 相关优化
  • 2. EXISTS & NOT EXISTS
    • 2.1 基本使用
    • 2.2 工作原理
    • 2.3 相关优化
  • 3. 两者区别

1. IN & NOT IN

ININ用于判断某个字段的值是否存在于给定的值列表中,常用于简单的列表匹配。可以使用单个值,也可以使用一个由多个值组成的列表,也可以是一个子查询。以下是IN关键词的示例用法:

1.1 基本使用

  • 📓 语法一:
SELECT * FROM table_name 
WHERE column_name IN (value1, value2, value3);-- 示例
SELECT * FROM employees WHERE department_id IN (1, 2, 3);

这将返回table_name表中满足条件的行,其中列column_name的值在给定的值列表(value1, value2, value3)中。

  • 📓 语法二:
SELECT * FROM table_name 
WHERE column_name IN (select column_name_b from table_name_b  WHERE condition );-- 示例
SELECT * FROM employees WHERE department_id IN (SELECT id FROM departments WHERE name = 'WorkDog');

其实与上面的用法是一样的,只是将给定的值列表换成了 table_name_b 表中的某个字段的值。先查出对应字段的所有值,然后再与前面表 table_namecolumn_name 字段进行值比较,返回table_name表中满足条件的行。

1.2 工作原理

在MySQL中,IN 语句用于检查某个值是否在指定的列表或子查询结果集中。IN 语句的工作原理包括处理静态值列表和子查询结果集。在不同的情况下,MySQL会采用不同的策略来执行 IN 语句。下面详细解释 IN 语句的工作原理。

1.2.1 静态值列表的 IN 语句

对于静态值列表,MySQL会将列表中的每个值与目标列的值进行比较。如果目标值在列表中,条件为真。

📓 假设有两个表 employees ,查询指定 department_id 的部门:

SELECT * 
FROM employees 
WHERE department_id IN (1, 2, 3);

👽 执行过程如下:

  1. 解析查询:MySQL解析查询语句。
  2. 执行计划:MySQL生成执行计划,决定如何访问 employees 表。
  3. 逐行扫描:对于 employees 表中的每一行,MySQL检查 department_id 列是否为 1、2 或 3。
  4. 返回结果:匹配的行被返回。

在这个过程中,MySQL对每一行执行简单的比较操作。这种情况下的 IN 语句等价于多个 OR 条件。

SELECT * 
FROM employees 
WHERE department_id = 1 OR department_id = 2 OR department_id = 3;

1.2.2 子查询的 IN 语句

IN 语句包含子查询时,MySQL必须先执行子查询并获取结果集,然后将主查询中的值与子查询结果集中的值进行比较。

📓 示例:

SELECT * 
FROM employees 
WHERE department_id IN (SELECT id FROM departments WHERE name = 'WorkDog');

👽 执行过程如下:

  1. 解析查询:MySQL解析主查询和子查询。
  2. 执行子查询:MySQL执行子查询 SELECT id FROM departments WHERE name = 'WorkDog',生成结果集。
  3. 缓存结果集:将子查询的结果集缓存到内存中。
  4. 执行主查询:MySQL生成主查询的执行计划。
  5. 逐行扫描:对于 employees 表中的每一行,MySQL检查 department_id 列是否在子查询结果集中。
  6. 返回结果:匹配的行被返回。

在这种情况下,子查询的执行方式会影响整体查询的性能。如果子查询结果集较大,MySQL可能会使用临时表来存储结果集,并使用索引来加快查找速度。

🌟 结果集缓存

当使用 IN 子查询时,MySQL会将子查询的结果集缓存到内存中以加快主查询的执行。对于非常大的结果集,这可能会导致内存占用过多。在这种情况下,可以考虑使用临时表或其他优化方法来降低内存使用。

1.3 相关优化

  1. 如果子查询返回的结果集较大,使用 EXISTS 可能会更有效,因为 EXISTS 会在找到匹配的行后立即停止子查询的执行。
  2. 静态值列表:确保在用于比较的列上有适当的索引。例如,上面的 1.2.1 例子 department_id 列上创建索引。
  3. 子查询:确保子查询中使用的列上有适当的索引。例如,上面的 1.2.2 例子中 departments.iddepartments.name 列上创建索引。
  4. IN 子查询转换为 JOIN 操作,例如:
    -- 使用IN子查询
    SELECT * 
    FROM employees 
    WHERE department_id IN (SELECT id FROM departments WHERE name = 'WorkDog');-- 转换为JOIN
    SELECT e.* 
    FROM employees e
    JOIN departments d ON e.department_id = d.id
    WHERE d.name = 'WorkDog';
    

2. EXISTS & NOT EXISTS

EXISTSEXISTS用于判断是否存在满足子查询条件的结果,常用于复杂的条件检查。子查询可以是一个查询语句,返回一个结果集。

2.1 基本使用

以下是EXISTS关键词的示例用法, NOT EXISTS 同理:

SELECT column_name FROM table_name1 
WHERE EXISTS (SELECT column_name FROM table_name2 WHERE condition
);-- 示例
SELECT * FROM employees e WHERE EXISTS (SELECT 1 FROM departments d WHERE d.name = 'WorkDog' AND e.department_id = d.id);

这将返回table_name1表中满足EXISTS子查询条件的行,子查询是在table_name2表中的一个查询。如果子查询返回结果集,则认为条件满足。

2.2 工作原理

当 MySQL 处理一个包含 EXISTS 子查询的查询时,它会逐条扫描外表的每一行,并对每一行执行一次子查询。如果子查询返回至少一行结果,那么 EXISTS 条件就满足,主查询的那一行就会被包含在最终结果集中,否则只查询的那一行就会被舍弃。

📓 假设有两个表 employeesdepartments,希望找到所有在特定部门(例如 WorkDog)工作的员工:

SELECT * 
FROM employees e 
WHERE EXISTS (SELECT 1 FROM departments d WHERE e.department_id = d.id AND d.name = 'WorkDog'
);

👽执行过程如下:

  1. 初始化:MySQL 初始化主查询,开始扫描 employees 表。
  2. 逐行扫描外表:对 employees 表中的每一行,执行以下步骤:
    • 读取一行:读取当前行的 department_id。
    • 执行子查询:针对当前行的 department_id 执行子查询
    SELECT 1 
    FROM departments d 
    WHERE e.department_id = d.id AND d.name = 'WorkDog'
    
    • 检查子查询结果:如果子查询返回至少一行结果,则 EXISTS 条件满足(true),这一行会被包含在结果集中。如果子查询不返回任何结果,则 EXISTS 条件不满足(false),这一行会被排除在结果集之外。
  3. 继续扫描:重复步骤2,直到扫描完 employees 表的所有行。
  4. 返回结果:将满足 EXISTS 条件的所有行作为结果返回。

2.3 相关优化

由于 EXISTS 子查询对于外表中的每一行都会执行一次,这意味着子查询的性能对于整个查询的性能至关重要。

  1. 索引使用:确保子查询中的过滤条件上有适当的索引。这可以显著减少子查询的执行时间。

  2. 简化子查询:尽量简化子查询,使其只返回需要的最小数据量。例如,使用 SELECT 1 而不是 SELECT *

  3. 避免计算:避免在子查询中进行复杂的计算,可以在外部查询中处理这些计算。

3. 两者区别

(1) 用法:

  • IN 关键字可以与常量列表一起使用,也可以与子查询一起使用。适用于在某个字段的值与给定值列表之间进行匹配。它是基于字段值与值列表进行比较的操作符。
  • EXISTS 关键字只能与子查询一起使用。适用于检查是否存在满足子查询条件的结果。它是基于子查询是否返回结果集进行判断的条件。

(2) 功能:

  • IN 关键字用于在一个查询中匹配一个值是否存在于一个列表中。
  • EXISTS 关键字用于检查子查询是否返回任何行。

(3) 子查询结果:

  • IN 关键字的子查询返回的结果集可以是给定的多个值列表,或者是一个单独的查询语句(返回结果必须只有一个字段)。
  • EXISTS 关键字的子查询通常返回一个布尔值,表示子查询是否返回了任何行。

(4) 性能:

  • IN 通常比 EXISTS 更快,尤其是在值列表较小时。因为它不需要执行额外的逻辑来检查是否存在结果。
  • EXISTS 关键字在处理大量数据时比 IN 关键字更高效。这是因为 EXISTS 只需要找到匹配的行,并返回结果,而不需要返回整个列表;性能可能会受到子查询的复杂性和数据量的影响。

(5) 空值处理:

INEXISTS对待空值的方式不同。

  • 使用IN时,如果给定的值列表中包含空值,将无法通过等值比较来匹配到空值。
  • EXISTS则可以判断子查询中是否存在空值结果。

在选择使用 IN 还是 EXISTS 关键字时,需要根据具体的查询需求和数据情况进行考虑。如果只是简单的匹配值是否在列表中,可以使用 IN。如果需要根据子查询的返回结果来决定外部查询的结果,或者需要处理大量数据,那么使用 EXISTS 可能更为适合。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 前端书籍翻页效果
  • 【proteus经典实战】定时器控制交通灯指示灯
  • Eureka: 微服务架构中的服务发现与注册实践
  • Python 潮流周刊#61:PyPI 管理员密钥泄露事件(摘要)
  • 【面试题】手撕缓存LRU
  • 开放开源开先河(三)
  • python需要掌握那些语法
  • 【Mysql关于读已提交和可重复读(Read Committed)隔离级别下解决幻读的方案】
  • python--实验15 数据分析与可视化
  • Python爬虫——1爬虫基础(一步一步慢慢来)
  • 【golang-ent】go-zero框架 整合 ent orm框架 | 解决left join未关联报错的问题
  • window11 部署llama.cpp并运行Qwen2-0.5B-Instruct-GGUF
  • python实现插入排序、快速排序
  • 陪玩系统小程序模式APP小程序H5系统搭建开发
  • 微信小程序-组件通信
  • Angular 4.x 动态创建组件
  • canvas 绘制双线技巧
  • Create React App 使用
  • CSS 提示工具(Tooltip)
  • Javascript Math对象和Date对象常用方法详解
  • JavaScript 一些 DOM 的知识点
  • rc-form之最单纯情况
  • React Transition Group -- Transition 组件
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • scala基础语法(二)
  • Swift 中的尾递归和蹦床
  • 从PHP迁移至Golang - 基础篇
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 基于HAProxy的高性能缓存服务器nuster
  • 技术:超级实用的电脑小技巧
  • 前端面试题总结
  • 微信小程序实战练习(仿五洲到家微信版)
  • ​经​纬​恒​润​二​面​​三​七​互​娱​一​面​​元​象​二​面​
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #图像处理
  • $L^p$ 调和函数恒为零
  • (a /b)*c的值
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (LeetCode C++)盛最多水的容器
  • (Oracle)SQL优化基础(三):看懂执行计划顺序
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)可以带来幸福的一本书
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .net refrector
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • .net中调用windows performance记录性能信息
  • @RequestMapping-占位符映射
  • [Android]Tool-Systrace
  • [C# 开发技巧]如何使不符合要求的元素等于离它最近的一个元素