当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL 大 IN 列表怎样理解索引估算成本

MySQL 大 IN 列表怎样理解索引估算成本

来源:17golang原创 2026-10-19 21:10:23 0浏览 收藏

大 IN 列表真正需要关注的不是 SQL 字符串有多长,而是 MySQL 为范围访问估算候选条件时要保留多少组合。单个 IN 列表中的每个值都会按一个 OR 条件计入;如果两个列各有一个列表,候选组合还可能按两个列表长度的乘积增长。先看范围优化是否因为内存上限被放弃,再决定拆分查询、改用临时表 JOIN,或只在当前会话调整上限。

官方手册:https://dev.mysql.com/doc/refman/8.4/en/range-optimization.html

要点速览
  • range_optimizer_max_mem_size 控制范围优化可用内存,超限时可能退回全表扫描等方案。
  • 两组 IN 的估算规模不是简单相加,通常要先看 M×N 的组合效应。
  • 调大上限只是诊断或短期缓解,稳定方案应让输入集合可控、可观察、可复用。

先判断:慢在列表长度,还是慢在范围候选膨胀

例如订单查询同时按客户和状态筛选:

-- 示例只用于观察计划,不代表真实运行结果
EXPLAIN FORMAT=JSON
SELECT id, total
FROM orders
WHERE customer_id IN (101, 102, 103, 104)
  AND status IN ('paid', 'shipped');

这里有两个候选集合。列表本身只有 4 个和 2 个值,但范围优化需要评估它们的组合关系。先记录 rows_examined、访问类型、使用的索引和成本估计,再与缩小列表后的计划比较。不要把“SQL 能执行”误认为“优化器一定走了索引”。

MySQL 大 IN 列表由客户集合、状态集合和范围优化器组成的静态查询结构说明图
图1:说明图,展示两组 IN 集合如何共同进入范围优化估算,不是运行截图或执行证据。

用 EXPLAIN、警告和 trace 找到估算退化点

MySQL 官方把 EXPLAIN 作为查看优化器计划的入口;如果范围优化的内存容量不足,可能出现 3170 警告,提示该语句没有完成范围优化。可以在同一会话先检查变量和警告:

-- 先确认当前会话的范围优化内存上限
SELECT @@session.range_optimizer_max_mem_size;

-- 运行目标查询后立即查看本会话警告
SHOW WARNINGS;

-- 只在诊断窗口临时提高上限,避免直接改变全局配置
SET SESSION range_optimizer_max_mem_size = 16777216;

若要解释“为什么选了这个访问路径”,可以开启当前会话的优化器跟踪,再查询 INFORMATION_SCHEMA.OPTIMIZER_TRACE。跟踪要在同一连接完成,结束后关闭;它适合定位范围候选、成本比较和被放弃的访问方式,不适合当作长期生产日志。

-- 只让当前会话记录优化过程,避免影响其他连接
SET SESSION optimizer_trace = 'enabled=ON';

-- 执行待诊断的 SELECT;正文中的集合按业务数据替换
SELECT id FROM orders WHERE customer_id IN (101,102,103,104);

-- 读取最近一次跟踪结果
SELECT TRACE FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

-- 诊断结束后关闭跟踪
SET SESSION optimizer_trace = 'enabled=OFF';

两组 IN 为什么要按乘积估算

官方文档给出的判断很实用:单个 IN 中的每个字面量相当于一个 OR 条件;当出现两个列表时,OR 条件数量按列表长度相乘。假设客户列表有 800 个值、地区列表有 20 个值,粗略组合规模就是 16000,而不是 820。多列索引、连接条件和其他 OR 约束还会继续增加实际成本,所以不能用一个固定阈值覆盖所有表。

场景优先观察更稳妥的处理
单个列表偶尔偏大Warning、rows 与计划类型按批次拆分并合并结果
多个列表长期组合组合规模与 trace 中的 range_optimizer把集合落到临时表后 JOIN
同一集合反复使用临时表索引和事务范围复用临时表,减少重复解析
MySQL 大 IN 列表在批量拆分、临时表 JOIN 与会话上限之间的方案边界说明图
图2:结构说明图,比较集合规模、拆分查询和临时表 JOIN 的静态边界,不是性能实测图。

拆分、临时表与调参:按生命周期选择方案

列表只偶尔超过上限时,可以按 200~500 个值分批查询,再在应用层合并并去重;批大小应由真实计划和延迟预算决定,不要把示例数字当成通用规则。列表来自用户上传或批处理任务、且需要与多列条件组合时,更适合写入临时表并为连接列建立索引,再用 JOIN 让优化器处理关系。

-- 把批量 ID 放入临时表,避免在主查询中展开超长 IN
CREATE TEMPORARY TABLE tmp_customer_ids (
  customer_id BIGINT PRIMARY KEY -- 主键帮助 JOIN 定位集合成员
);

-- 应用层批量写入待查询的客户 ID
INSERT INTO tmp_customer_ids (customer_id) VALUES (101), (102), (103);

-- 用关系连接替代大 IN,并保留主表上的业务过滤条件
SELECT o.id, o.total
FROM orders AS o
JOIN tmp_customer_ids AS ids ON ids.customer_id = o.customer_id
WHERE o.status = 'paid';

临时表不是免费的:要考虑写入成本、索引维护、事务生命周期和连接池复用。若只是为了验证“提高上限是否改变计划”,可以用会话级 SET 做对照;确认根因后再决定是否改配置。生产环境不建议为了绕过一次警告而无限调大内存,因为并发查询会共同放大资源压力。

常见问题

大 IN 列表一定比临时表 JOIN 慢吗?

不一定。集合很小且只执行一次时,IN 可能更简单;集合大、重复使用或与多列条件组合时,临时表 JOIN 往往更容易控制成本。

EXPLAIN ANALYZE 能直接证明范围优化内存超限吗?

不能。它用于比较实际执行与估算结果,超限线索仍应先看 Warning 3170,并结合变量和 optimizer trace 判断。

应该直接把 range_optimizer_max_mem_size 设为 0 吗?

不应直接这么做。0 表示不限制,适合受控诊断,不等于生产环境的稳定优化方案;先缩小集合或改变数据承载方式更安全。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
MySQL 不可见索引被 USE INDEX 指定时为什么报错MySQL 不可见索引被 USE INDEX 指定时为什么报错
上一篇
MySQL 不可见索引被 USE INDEX 指定时为什么报错
MySQL optimizer_trace 查看范围优化决策路径的配置方法
下一篇
MySQL optimizer_trace 查看范围优化决策路径的配置方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    548次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    601次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    628次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    581次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    405次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码