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

mysql 回表查询(二次查询,如何检查,如何规避)

h5打开以查看

“回表查询”通常发生在使用二级索引(Secondary Index)的查询中。当查询所需的数据列并不全部包含在二级索引中时,即使使用了索引,MySQL 也需要根据索引记录中的主键值,回到聚簇索引(Clustered Index)的主键 B+Tree 中去查找完整的行数据,这个过程就叫做“回表”。


核心方法:使用 EXPLAIN 命令

检测回表查询最主要、最直接的工具就是 MySQL 的 EXPLAIN 命令。你需要重点关注 EXPLAIN 输出中的以下几个字段:

1. type (访问类型)

这个字段显示了 MySQL 决定如何查找表中的行。

  • eq_ref, ref, range, index_scan: 这些通常是好的类型,表示使用了索引的有效查找。

  • index: 这是一个关键信号! type = index 通常意味着 MySQL 正在扫描整个二级索引(全索引扫描)。这通常发生在需要从索引中获取大量数据,然后回表的情况下。它比全表扫描(ALL)快,但依然不高效。

  • ALL: 最坏的情况,全表扫描,根本没用上索引。

2. key 和 key_len (使用的索引)
  • key: 显示 MySQL 实际决定使用的索引。

  • key_len: 显示使用的索引键的长度。通过这个长度,你可以判断索引是否被完全使用(覆盖了查询条件的所有列)。如果 key_len 小于索引定义的长度,说明只使用了索引的前面一部分,这可能不是最优的。

3. Extra (额外信息)

这是判断回表最重要的字段

  • Using index: 这是最理想的情况,表示出现了“覆盖索引”(Covering Index)。查询的所有字段都包含在使用的索引中,MySQL 只需要读取索引即可返回结果,完全不需要回表。这是优化的重要目标。

  • Using index condition: 表示使用了 Index Condition Pushdown (ICP) 优化,服务器层将部分条件(WHERE 子句)下推给存储引擎层进行过滤,但仍然可能需要回表

  • Using where: 这通常意味着需要回表。表示存储引擎从索引中读取行后,需要在 MySQL 服务器层再根据 WHERE 条件进行过滤。服务器层过滤的数据,就是已经从聚簇索引中取回的完整行数据。


实战演示:如何一步步检测

假设我们有一张用户表 users

sql

CREATE TABLE `users` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(100) DEFAULT NULL,`age` int DEFAULT NULL,`city` varchar(100) DEFAULT NULL,`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`),KEY `idx_name_age` (`name`,`age`) -- 一个联合索引
) ENGINE=InnoDB;
场景 1:覆盖索引,无需回表(理想情况)

sql

EXPLAIN SELECT name, age FROM users WHERE name = 'John';

分析 EXPLAIN 结果:

  • typeref (使用了索引等值查询)

  • keyidx_name_age (使用了我们创建的联合索引)

  • ExtraUsing index

    • 结论:太好了!查询的 name 和 age 字段都包含在 idx_name_age 索引中。MySQL 只需读取索引文件,无需回表,性能极高。

场景 2:需要回表的查询(常见情况)

sql

EXPLAIN SELECT * FROM users WHERE name = 'John';
-- 或者
EXPLAIN SELECT name, age, city FROM users WHERE name = 'John'; -- city 不在索引中

分析 EXPLAIN 结果:

  • typeref (依然使用了索引)

  • keyidx_name_age (使用了索引来快速定位记录)

  • ExtraNULL 或者 Using where

    • 结论:发生了回表。idx_name_age 索引中只有 (name, age, id)(id是主键,会自动附加到二级索引中),但没有 city 字段。为了获取 city 和 created_at 等所有字段,MySQL 必须根据找到的 id 值,回到聚簇索引中去查找完整的行数据。

场景 3:全索引扫描,然后回表

sql

EXPLAIN SELECT * FROM users WHERE age > 20;

分析 EXPLAIN 结果:

  • typeindex

  • keyidx_name_age

  • ExtraUsing where

    • 结论:这是一个非常典型的低效查询。我们的索引是 (name, age),但查询条件从 age 开始,无法使用索引的最左前缀原则。因此,MySQL 会选择扫描整个 idx_name_age 索引,对每一条索引记录检查 age > 20 的条件,然后为每一个匹配的索引记录回表获取完整数据。性能很差。


总结:检测与优化回表查询的步骤

  1. 使用 EXPLAIN: 对任何性能存疑的查询都使用 EXPLAIN 分析。

  2. 查看 Extra 列

    • 如果看到 Using index,恭喜你,没有回表。

    • 如果看到 Using where 且 type 是 ref 或 index,很可能发生了回表。

  3. 查看 type 列: 如果值是 index,说明正在全索引扫描,通常伴随着大量回表,需要优化。

  4. 优化策略

    • 创建覆盖索引: 如果回表查询很频繁,考虑创建一个“覆盖索引”,将查询中涉及的所有字段(SELECT 和 WHERE 中的字段)都包含在索引中。例如,对于 SELECT id, name, city FROM users WHERE name = ?,可以创建索引 (name, city) 或 (name, city, id) 来覆盖查询。

    • 避免 SELECT *: 只获取你真正需要的列,减少需要回表获取的数据量,也更容易实现覆盖索引。

    • 使用索引的最左前缀原则: 确保查询条件能有效利用索引。

通过系统性地使用 EXPLAIN 并关注上述关键字段,你可以准确地识别和优化数据库中的回表查询,从而极大提升查询性能。

h5打开以查看


文章转载自:

http://9cvk7e9m.dkgjL.cn
http://fOPhcV3t.dkgjL.cn
http://5BCOhJVZ.dkgjL.cn
http://4yoRXgvo.dkgjL.cn
http://KEGaP6MV.dkgjL.cn
http://zZ6LK6IZ.dkgjL.cn
http://rzDIC6V7.dkgjL.cn
http://fk6FLZIO.dkgjL.cn
http://48cXlYX2.dkgjL.cn
http://7vAhnzBR.dkgjL.cn
http://FEmVJDTG.dkgjL.cn
http://lg3fqppF.dkgjL.cn
http://Rnve7tf3.dkgjL.cn
http://K0tQkLPa.dkgjL.cn
http://6c5LfLX2.dkgjL.cn
http://sSlWSz8G.dkgjL.cn
http://BKnV2Q38.dkgjL.cn
http://PPPD6g1G.dkgjL.cn
http://bIuKb6Qc.dkgjL.cn
http://NuKGRe8e.dkgjL.cn
http://UvJ9s62T.dkgjL.cn
http://z27VwaM7.dkgjL.cn
http://uZHzO9MR.dkgjL.cn
http://AwOkugs3.dkgjL.cn
http://x6iMSr1z.dkgjL.cn
http://X94R8Y7O.dkgjL.cn
http://lWq4HqkS.dkgjL.cn
http://EVEFD7wY.dkgjL.cn
http://cjU6BNWq.dkgjL.cn
http://nZ8zpI0n.dkgjL.cn
http://www.dtcms.com/a/372761.html

相关文章:

  • vue3+ts使用html2canvas,实现页面截图
  • 疾病语音数据集 WAV格式音频
  • 07 下载配置很完善的yum软件源
  • 【PCIe EP 设备入门学习专栏 -- 8.2.2 PCIe EP Controller Register Types 介绍】
  • 排序---冒泡排序(Bubble Sort)
  • C++/QT day8(9.8)
  • 【Linux网络编程】传输层协议-----UDP协议
  • 医疗连续体机器人模块化控制界面设计与Python库应用研究(上)
  • 分享|构建产教融合的一体化人工智能实验室综合解决方案
  • 从固定 px 到响应式:Vue + Vite 项目响应式改造实战,解决前端不适配的问题
  • java面试:了解MVCC么,详细解释一下
  • ChatGPT 协作调优:把 SQL 查询从 5s 优化到 300ms 的全过程
  • 长春高新需要新叙事
  • Python用PSO优化SVM与RBFN在自动驾驶系统仿真、手写数字分类应用研究
  • android studio JNI 环境配置实现 java 调用 c/c++
  • 安卓非原创--基于Android Studio 实现的新闻App
  • Flutter Android Studio开发实用技巧
  • Android Studio适配butterknife遇到的坑
  • 论文精读(五):面向链接预测的知识图谱表示学习方法综述
  • 使用AI工具一句话生成PPT
  • 《嵌入式硬件(五):IMX6ULL所需的基础》
  • Vue响应式更新 vs React状态更新:两种范式的底层逻辑与实践差异
  • Qt UDP 网络编程详解
  • CUPP针对性字典安全防范
  • 用nasm汇编器汇编不同位数格式的ELF
  • odoo打印pdf速度慢问题
  • 京东商品评论 API(JSON 数据返回)核心解析
  • SpringMVC(二)
  • 开始理解大型语言模型(LLM)所需的数学基础
  • 搭论文大纲逻辑乱易跑题?AI 3 步梳理框架,自动串逻辑链