MySQL中IN关键字与EXIST关键字的比较

文章目录

      • **功能等价性分析**
        • **执行计划分析**:
      • **1. `EXISTS` 的工作原理**
        • **步骤拆解**:
      • **2. 为什么需要“利用索引快速定位”?**
        • **索引作用示例**:
      • **3. 与 `IN` 子查询的对比**
        • **`IN` 的工作方式**:
        • **关键差异**:
      • **4. 性能优化核心**
      • **5. 实际案例验证**
        • **场景**:
        • **执行计划分析**:
        • **结果**:
      • **6. 总结**
        • **效率总结**:
      • **5. 最终建议**

问题:
首先说明下面两句MYSQL语句实现的功能是否一样,接着比较它们的执行效率:

SELECT * from tableA where tableA.id in (select id from tableB)
SELECT * FROM tableA 
WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.id = tableB.id);

答:当 id 无 NULL 值且唯一时,两者功能一致。另外,第二句中的子查询使用 SELECT 1(最佳实践,无需实际列值)。通常情况下(id是主键,tableA 和 tableB 数据量较大,id 字段有索引。),第二句效率更高。


功能等价性分析

场景IN 的行为EXISTS 的行为
子查询无 NULL等价等价
子查询含 NULLtableA.id IN (1, NULL) 等价于 tableA.id=1 OR tableA.id=NULL,最终只有 id=1 的行匹配EXISTS 只要子查询有匹配(即使含 NULL)就会返回 TRUE

结论

  • tableB.id NULL 值且唯一时,两者功能一致。
  • tableB.idNULL 或重复值时,结果可能不同。

执行计划分析
方法优化策略适用场景
IN 子查询MySQL 可能将子查询物化为临时表,再通过 JOIN 或半连接优化。子查询结果集较小时效率高。
EXISTStableA 的每一行触发一次关联子查询,利用索引快速定位。tableA 较小且 tableB.id 有索引时效率高。

1. EXISTS 的工作原理

EXISTS 是一种 关联子查询(Correlated Subquery),其核心逻辑是:
对于外层查询(tableA)的每一行,触发一次内层子查询(tableB)的检查
具体流程如下:

步骤拆解
  1. 遍历外层表(tableA
    逐行读取 tableA 的数据,取当前行的 id 值(例如 id=100)。

  2. 执行子查询(tableB
    将外层 tableA.id=100 传入子查询,检查 tableB 中是否存在匹配的 id

    SELECT 1 FROM tableB WHERE id = 100;  -- 当前外层行的 id 值
    
  3. 判断结果

    • 若子查询返回至少一行结果 → EXISTSTRUE → 保留当前外层行。
    • 若子查询无结果 → EXISTSFALSE → 丢弃当前外层行。
  4. 循环处理
    重复上述过程,直到 tableA 所有行处理完毕。


2. 为什么需要“利用索引快速定位”?

在上述流程中,子查询 SELECT 1 FROM tableB WHERE id=100 需要快速判断 id=100 是否存在。
tableB.id 没有索引

  • 数据库需对 tableB 进行全表扫描 → 时间复杂度为 O(N),性能极差(尤其当 tableB 数据量大时)。

tableB.id 有索引(如主键索引或普通索引):

  • 数据库通过索引(如 B+Tree)直接定位到 id=100 → 时间复杂度为 O(logN),效率极高。
索引作用示例
  • 假设 tableB 有 100 万行数据:
    • 无索引:每次子查询需扫描 100 万行 → 总成本:1,000,000(外层行数) × 1,000,000(内层扫描) → 不可接受。
    • 有索引:每次子查询仅需 3~4 次磁盘 I/O(B+Tree 高度) → 总成本:1,000,000(外层行数) × 4(索引查询) → 高效。

3. 与 IN 子查询的对比

IN 的工作方式
SELECT * FROM tableA WHERE id IN (SELECT id FROM tableB);
  1. 执行子查询
    先执行 SELECT id FROM tableB,生成一个临时结果集(如 [1, 2, 3])。

  2. 遍历外层表(tableA
    逐行检查 tableA.id 是否在临时结果集中。

关键差异
特性EXISTSIN
子查询执行次数外层表行数(N次)1次
临时表物化无需物化需要物化子查询结果到临时表
索引依赖依赖内层表(tableB)的索引依赖外层表(tableA)的索引
NULL 值处理不受子查询中 NULL 影响IN 遇到 NULL 可能导致结果异常

4. 性能优化核心

  • EXISTS 高效的核心条件

    • 内层表(tableB)的关联字段(id)必须有索引。
    • 外层表(tableA)的数据量不宜过大(否则逐行触发子查询的总成本仍可能较高)。
  • IN 高效的核心条件

    • 子查询结果集较小,且外层表(tableA)的 id 字段有索引。

5. 实际案例验证

场景
  • tableA:10,000 行,id 无索引
  • tableB:1,000,000 行,id 有唯一索引
执行计划分析
  1. EXISTS 查询

    • tableA 的 10,000 行逐行触发子查询。
    • 每次子查询通过索引在 tableB 中快速定位 → 总成本 ≈ 10,000 × 4 I/O = 40,000 I/O。
  2. IN 查询

    • 先执行 SELECT id FROM tableB,生成 1,000,000 行的临时表。
    • tableA 的 10,000 行逐行在临时表中搜索 → 总成本 ≈ 1,000,000(物化) + 10,000 × 1,000,000(全扫描) → 性能灾难。
结果
  • EXISTS 明显优于 IN,尤其在子查询结果集大且内层表有索引时。

6. 总结

  • EXISTS 的本质:通过外层表驱动循环 + 内层索引快速定位,避免全表扫描。
  • 何时选择 EXISTS
    • 内层表(子查询表)的关联字段有索引。
    • 外层表数据量适中,或内层表数据量远大于外层表。
  • 验证方法
    EXPLAIN SELECT * FROM tableA 
    WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.id = tableB.id);
    
    检查执行计划中是否出现 Using index(表示索引生效)。
效率总结
  1. EXISTS 通常更高效
    • 避免物化临时表。
    • 通过索引快速判断是否存在匹配。
  2. IN 可能更高效的情况
    • 子查询结果集非常小且无索引。
    • 优化器将 IN 转换为 JOIN 并应用哈希/排序优化。

5. 最终建议

  • 优先使用 EXISTS:语义更清晰,且通常性能更优。
  • 强制功能一致性:若需严格匹配 IN 的行为(处理 NULL),可添加过滤条件:
    SELECT * FROM tableA 
    WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.id = tableB.id AND tableB.id IS NOT NULL  -- 显式排除 NULL 值
    );
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/897685.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

## DeepSeek写水果记忆配对手机小游戏

DeepSeek写水果记忆配对手机小游戏 提问 根据提的要求,让DeepSeek整理的需求,进行提问,内容如下: 请生成一个包含以下功能的可运行移动端水果记忆配对小游戏H5文件: 要求 可以重新开始游戏 可以暂停游戏 卡片里的水果…

【含文档+PPT+源码】基于Django框架的乡村绿色农产品交易平台的设计与实现

项目介绍 本课程演示的是一款基于Django框架的乡村绿色农产品交易平台的设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Python学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运…

idea超级AI插件,让 AI 为 Java 工程师

引言​ 用户可在界面中直接通过输入自然语言的形式描述接口的需求,系统通过输入的需求自动分析关键的功能点有哪些,并对不确定方案的需求提供多种选择,以及对需求上下文进行补充,用户修改确定需求后,系统会根据需求设…

@RestControllerAdvice注解

RestControllerAdvice RestControllerAdvice 是 Spring Framework(3.2)和 Spring Boot 中用于全局处理控制器层异常和统一响应格式的注解。它结合了 ControllerAdvice 和 ResponseBody 的功能,能够拦截控制器方法抛出的异常,并以 …

ActiveMQ监听器在MQ重启后不再监听问题

应用的监听器注解 JmsListener(destination "TopicName",containerFactory "FactoryName")工厂代码 BeanJmsListenerContainerFactory<?> FactoryName(ConnectionFactory connectionFactory){SimpleJmsListenerContainerFactory factory new S…

大白话 Vue 中的keep - alive组件,它的作用是什么?在什么场景下使用?

大白话 Vue 中的keep - alive组件&#xff0c;它的作用是什么&#xff1f;在什么场景下使用&#xff1f; 什么是 keep-alive 组件 在 Vue 里&#xff0c;keep-alive 是一个内置组件&#xff0c;它就像是一个“保存盒”&#xff0c;能把组件实例保存起来&#xff0c;而不是每次…

考研复试c语言常见问答题汇总2

11. 关键字和一般标识符有什么不同&#xff1f; C语言中关键字与一般标识符区别&#xff1a; 定义&#xff1a;关键字是C语言预定义的特殊单词&#xff08;如int、for&#xff09;&#xff0c;有固定含义&#xff1b;标识符是自定义的名称&#xff08;如变量名、函数名&#xf…

Scala编程_实现Rational的基本操作

在Scala中实现一个简单的有理数&#xff08;Rational&#xff09;类&#xff0c;并对其进行加法、比较等基本操作. 有理数的定义 有理数是可以表示为两个整数的比值的数&#xff0c;通常形式为 n / d&#xff0c;其中 n 是分子&#xff0c;d 是分母。为了确保我们的有理数始终…

若依框架-给sys_user表添加新字段并获取当前登录用户的该字段值

目录 添加字段 修改SysUser类 修改SysUserMapper.xml 修改user.js 前端获取字段值 添加字段 若依框架的sys_user表是没有age字段的&#xff0c;但由于业务需求&#xff0c;我需要新添加一个age字段&#xff1a; 修改SysUser类 添加age字段后&#xff0c;要在SysUser类 …

霍夫变换法是基于传统视觉特征的道路车道线检测算法中的一种经典方法

霍夫变换法是基于传统视觉特征的道路车道线检测算法中的一种经典方法&#xff0c;以下是对它的详细介绍&#xff1a; 基本原理 霍夫变换的基本思想是将图像空间中的点映射到参数空间中&#xff0c;通过在参数空间中寻找峰值来确定图像中特定形状的参数。在车道线检测中&#…

【论文笔记】Best Practices and Lessons Learned on Synthetic Data for Language Models

论文信息 论文标题&#xff1a;Best Practices and Lessons Learned on Synthetic Data for Language Models 作者信息&#xff1a; Ruibo Liu, Jerry Wei, Fangyu Liu, Chenglei Si, Yanzhe Zhang, Jinmeng Rao, Steven Zheng, Daiyi Peng, Diyi Yang, Denny Zhou1 and Andre…

Android调试工具之ADB

Android Debug Bridge ADB介绍**一、ADB下载****二、ADB安装****三、ADB基础使用命令** ADB介绍 ADB&#xff08;Android Debug Bridge&#xff09;是Android开发与调试的必备工具&#xff0c;掌握它能极大提升开发效率。 一、ADB下载 Windows版本&#xff1a;https://dl.goo…

第三篇《RMAN 备份与恢复指南:保障数据库安全》(RMAN)

《Oracle 数据迁移与备份系列》 第三篇&#xff1a;《RMAN 备份与恢复指南&#xff1a;保障数据库安全》&#xff08;RMAN&#xff09; 1.概述 RMAN&#xff08;Recovery Manager&#xff09; 是 Oracle 数据库内置的专用备份与恢复工具&#xff0c;提供高效、安全的物理级数…

【测试框架篇】单元测试框架pytest(4):assert断言详解

一、前言 用例三要素之一就是对预期结果的断言。 何为断言&#xff1f;简单来说就是实际结果和期望结果去对比&#xff0c;符合预期就测试pass&#xff0c;不符合预期那就测试 failed。断言内容就是你要的预期结果。断言包含对接口响应内容做断言、也包含对落DB的数据做断言。…

什么是大模型微调?

在大模型&#xff08;如GPT、BERT、LLaMA等&#xff09;广泛应用的今天&#xff0c;“微调”&#xff08;Fine-Tuning&#xff09;已成为释放模型潜力的关键技术。它通过针对特定任务调整预训练模型&#xff0c;使其从“通才”变为“专才”。本文将从概念、原理到实践&#xff…

C# Channel

核心概念创建Channel无界通道有界通道FullMode选项 生产者-消费者模式生产者写入数据消费者读取数据 完整示例高级配置优化选项&#xff1a;取消操作&#xff1a;通过 CancellationToken 取消读写。 错误处理适用场景Channel的类型创建Channel写入和读取消息使用场景示例代码注…

基于Spring Boot的牙科诊所管理系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

upload-labs-靶场(1-19关)通关攻略

文件上传漏洞是指由于程序员再开发时&#xff0c;未对用户上传的文件进行严格的验证和过滤&#xff0c;而导致用户可以上传可执行的动态脚本文件 Pass-01&#xff08;前端验证绕过&#xff09; 上传111.php文件&#xff0c;发现弹窗显示不允许&#xff0c;并给出白名单文件类…

使用 pytesseract 进行 OCR 识别:以固定区域经纬度提取为例

引言 在智能交通、地图定位等应用场景中&#xff0c;经常会遇到需要从图像中提取经纬度信息的需求。本篇文章将介绍如何利用 Python 的 pytesseract 库结合 PIL 对图像进行预处理&#xff0c;通过固定区域裁剪&#xff0c;来有效地识别出图像上显示的经纬度信息。 1. OCR 与 …

docker安装和卸载

服务器系统&#xff1a;Ubuntu Server 18.04.2 64bit 1 安装docker&#xff1a; 1.1 在线安装 1.# yum install docker 1.2 离线安装 https://download.csdn.net/download/qq_27106141/90477700 1.# docker-18.03.1-ce.tgz 1.2.1 解压 tar -xzvf docker-18.03.1-ce.tgz 1.2.2…