游乐游手机版
首页/数据库/文章详情

MySQL面试调优:Explain、索引、慢查询及缓存架构

时间:2026-07-03 07:02
前言这篇文章系统梳理了 MySQL 查询慢的排查和优化方法,读完你可以用一套清晰思路回答性能调优类面试题。面试里问 MySQL 性能优化,最怕答成散点式。比如回一句“加索引”——然后呢?这显然不够。真正靠谱的回答,应该从 定位问题 开始,再到 索引优化、SQL 优化、分页优化、表结构优化、缓存和架构

前言

这篇文章系统梳理了 MySQL 查询慢的排查和优化方法,读完你可以用一套清晰思路回答性能调优类面试题。

MySQL性能调优面试复习小结之Explain、索引、慢查询、缓存和架构优化

面试里问 MySQL 性能优化,最怕答成散点式。比如回一句“加索引”——然后呢?这显然不够。真正靠谱的回答,应该从 定位问题 开始,再到 索引优化、SQL 优化、分页优化、表结构优化、缓存和架构优化,层层递进。核心目标就一句话:

让 MySQL 少扫描、少回表、少排序、少建临时表、少做无效 IO。

一、先用 EXPLAIN 定位问题

查询慢,不要上来就加索引。第一步应该是看执行计划。常用命令就是:

EXPLAIN SELECT * FROM user WHERE age = 18;

EXPLAIN 可以告诉你 MySQL 准备怎么执行这条 SQL。重点看下面这些字段:

字段含义重点
possible_keys可能使用的索引优化器发现的候选索引
key实际使用的索引NULL 说明没用索引
key_len实际使用的索引长度常用于判断联合索引用到几列
rows预估扫描行数越大越危险
type访问类型判断查询效率的关键
Extra额外信息看排序、临时表、覆盖索引

1. possible_keys 和 key 的区别

possible_keys 表示 MySQL 认为可能用得上的索引。key 表示最终真正用到的索引。比如:

possible_keys: idx_agekey: NULLtype: ALL

这说明 idx_age 理论上可用,但优化器最终没用,查询还是全表扫描。原因可能是数据量小、索引区分度低、回表成本高,或者统计信息不准确。

2. key_len 看联合索引用得深不深

假设有联合索引:

CREATE INDEX idx_name_age_city ON user(name, age, city);

如果 SQL 是:

SELECT * FROM user WHERE name = 'Tom' AND age = 18;

key_len 可以帮你判断索引用到了 name,还是用到了 name + age。它不是越长越好,它的价值是判断 联合索引是否被充分使用

3. rows 看扫描量大不大

rows 是优化器预估要扫描的行数。比如:

type: ALLrows: 1000000

这基本就是危险信号,它说明 MySQL 可能要扫描 100 万行。当然,rows 是估算值,如果统计信息不准,可以执行:

ANALYZE TABLE user;

让 MySQL 重新统计。

二、重点看 type:扫描方式决定效率

type 表示 MySQL 找数据的方式。常见类型从差到好大致是:

ALL < index < range < ref < eq_ref < const

1. ALL:全表扫描

ALL 是最差的情况,表示 MySQL 要扫描整张表:

type: ALLkey: NULL

这种情况通常要重点优化。

2. index:全索引扫描

index 是全索引扫描,它比全表扫描稍好一点,因为扫的是索引树。但本质还是从头扫到尾,数据量大时也很慢。

3. range:索引范围扫描

常见于:

WHERE age > 18WHERE price BETWEEN 10 AND 80WHERE id IN (1, 2, 3)

range 开始,索引作用就比较明显了。

4. ref:非唯一索引等值查询

比如:

SELECT * FROM user WHERE age = 18;

如果 age 是普通索引,可能出现 type: ref,因为 age = 18 可能匹配多行。

5. eq_ref:唯一索引关联查询

常见于多表 JOIN。比如订单表关联用户表:

SELECT *FROM orders oJOIN user u ON o.user_id = u.id;

如果 u.id 是主键或唯一索引,可能出现 eq_ref

6. const:主键或唯一索引查一行

比如:

SELECT * FROM user WHERE id = 1;

这种查询非常快。

三、Extra 里三个高频信号

Extra 是执行计划里的补充信息,面试里最常问这三个:

Using filesortUsing temporaryUsing index

1. Using filesort:额外排序

Using filesort 表示 MySQL 不能直接利用索引顺序完成排序,只能自己额外排序。注意,filesort 不一定真的写磁盘文件,它可能在内存里排,数据太大时才会落盘。比如:

SELECT * FROM user ORDER BY age;

如果 age 没有索引,MySQL 可能会:

扫描数据取出结果额外排序返回结果

优化方式是让排序字段走索引:

CREATE INDEX idx_age ON user(age);

2. Using temporary:使用临时表

Using temporary 表示 MySQL 创建了内部临时表保存中间结果。常见于 GROUP BYORDER BYDISTINCTUNION。比如:

SELECT age, COUNT(*)FROM userGROUP BY age;

如果不能利用索引完成分组,MySQL 可能会把中间结果放进临时表。临时表为什么慢?因为 MySQL 要额外写入中间结果,再读取、排序或分组,数据量大时还可能落盘。内部临时表可以有索引,但通常由 MySQL 自动决定。你优化的方向不是手动控制临时表,而是让原 SQL 能直接利用索引完成分组或排序。

3. Using index:覆盖索引

Using index 是好信号。它表示查询需要的数据只从索引里就能拿到,不需要回表。比如有索引:

CREATE INDEX idx_name_age ON user(name, age);

执行:

SELECT age FROM user WHERE name = 'Tom';

name 用于过滤,age 用于返回,两个字段都在索引里,这就是覆盖索引。

四、索引优化:不要只会说“加索引”

索引的本质是减少扫描范围,但不是越多越好,它会占空间,也会降低写入速度。

1. 哪些字段适合建索引

常见适合建索引的字段:经常出现在 WHERE 里的字段;经常用于 ORDER BY 的字段;经常用于 GROUP BY 的字段;多表 JOIN 的关联字段;区分度高的字段。比如:

SELECT * FROM orders WHERE user_id = 1001;

可以考虑:

CREATE INDEX idx_user_id ON orders(user_id);

2. 哪些字段不适合建索引

区分度很低的字段,比如性别、状态;很少用于查询条件的字段;经常更新的字段;小表上的普通字段;大文本字段的完整索引。比如 gender 只有男、女,建索引后筛选度很低,优化器可能仍然选择全表扫描。

3. 联合索引要遵循最左匹配原则

假设有联合索引:

CREATE INDEX idx_a_b_c ON t(a, b, c);

可以命中索引的情况:

WHERE a = 1WHERE a = 1 AND b = 2WHERE a = 1 AND b = 2 AND c = 3

不太能充分命中的情况:

WHERE b = 2WHERE c = 3WHERE b = 2 AND c = 3

因为缺少最左边的 a

4. 联合索引字段顺序怎么排

常见原则:等值查询字段放前面;区分度高的字段优先;高频查询字段优先;排序、分组字段尽量接在后面。比如高频 SQL 是:

SELECT *FROM ordersWHERE user_id = 1001 AND status = 1ORDER BY create_time DESC;

可以考虑:

CREATE INDEX idx_user_status_timeON orders(user_id, status, create_time);

这样既能过滤,也能帮助排序。

五、常见索引失效场景

很多慢 SQL 不是没索引,而是索引用不上。

1. 左模糊查询

WHERE name LIKE '%Tom'WHERE name LIKE '%Tom%'

这种通常无法走普通 B+Tree 索引。因为索引是从左到右有序的,如果你不知道开头是什么,MySQL 很难按索引定位。可以优化成右模糊:

WHERE name LIKE 'Tom%'

2. 对索引列使用函数

WHERE DATE(create_time) = '2026-06-08'

这样会让索引列参与函数计算。可以改成范围查询:

WHERE create_time >= '2026-06-08 00:00:00'  AND create_time <  '2026-06-09 00:00:00'

3. 对索引列做表达式计算

WHERE age + 1 = 19

可以改成:

WHERE age = 18

4. 隐式类型转换

如果 phone 是字符串类型,却这样写:

WHERE phone = 13800138000

可能发生隐式类型转换。应该写成:

WHERE phone = '13800138000'

5. OR 使用不当

WHERE name = 'Tom' OR age = 18

如果 name 有索引,但 age 没索引,可能导致索引效果变差。可以考虑给两个字段都建合适索引,或者拆成 UNION

6. 范围查询后的字段

联合索引中,范围查询后面的字段通常不能继续用于精确定位。比如索引:

CREATE INDEX idx_a_b_c ON t(a, b, c);

SQL:

WHERE a = 1 AND b > 10 AND c = 3

这里 a 可以用,b 可以做范围扫描,c 通常不能继续用于缩小索引扫描范围。

六、如果 MySQL 选错索引怎么办

有时 EXPLAIN 会发现优化器选了不合适的索引。不要第一反应就强制索引,先看三个问题:

  1. 统计信息是否不准;
  2. 索引区分度是否太低;
  3. SQL 是否让索引失效。

可以先更新统计信息:

ANALYZE TABLE products;

如果确认优化器确实选错了,可以使用索引提示。

1. USE INDEX

建议优化器考虑某个索引:

SELECT *FROM products USE INDEX (idx_buyprice)WHERE buyPrice BETWEEN 10 AND 80;

2. FORCE INDEX

强制 MySQL 尽量使用某个索引:

EXPLAIN SELECT productName, buyPriceFROM products FORCE INDEX (idx_buyprice)WHERE buyPrice BETWEEN 10 AND 80ORDER BY buyPrice;

如果生效,可能看到 key: idx_buypricetype: range

3. IGNORE INDEX

让优化器忽略某个索引:

SELECT *FROM products IGNORE INDEX (idx_name)WHERE buyPrice BETWEEN 10 AND 80;

但这些都属于干预手段,更推荐先从索引设计和 SQL 写法上解决。

七、查询优化:少查、少回表、少 JOIN

1. 避免 SELECT *

SELECT * 的问题很直接:它会查出整行数据,带来四类成本——更多的磁盘 IO、网络传输、应用反序列化,以及更容易破坏覆盖索引。比如你只需要:

SELECT id, name FROM user WHERE id = 1;

就不要写:

SELECT * FROM user WHERE id = 1;

2. 尽量使用覆盖索引

普通二级索引查询流程:查二级索引拿到主键 id → 回表查完整行 → 返回结果。覆盖索引查询流程:查二级索引直接拿到需要字段 → 返回结果。少了回表,自然更快。

3. JOIN 要小结果集驱动大结果集

JOIN 可以理解成嵌套循环。如果小表有 100 行,大表有 100 万行,理想方式是先查小结果集 100 行,每行去大表按索引查。反过来先扫大表 100 万行,每行去小表匹配,成本就高很多。更准确地说,不是物理小表驱动大表,而是 过滤后的小结果集驱动大结果集

4. 被驱动表关联字段要有索引

比如:

SELECT *FROM orders oJOIN user u ON o.user_id = u.id;

如果 u.id 是主键,匹配很快。如果被驱动表关联字段没索引,可能每次匹配都扫描一遍表,这会非常慢。

5. 高频 JOIN 可以考虑冗余字段

比如订单列表每次都要展示用户名,原设计是:

orders(id, user_id, amount)user(id, name)

每次都 JOIN 很麻烦。可以在订单表冗余:

orders(id, user_id, user_name, amount)

查询就变成单表。代价是数据冗余和一致性维护,适合读多写少、字段变化少的场景。订单商品名、下单价格这类历史快照字段,也很适合冗余。

八、分页优化:重点解决深分页

普通分页:

SELECT * FROM tb_sku LIMIT 200000, 10;

它不是直接跳到第 200000 行,MySQL 通常要先扫描前 200010 行,再丢掉前 200000 行。这就是深分页慢的原因。

1. 基于位置分页

如果主键自增,可以改成:

SELECT *FROM tb_skuWHERE id > 200000ORDER BY idLIMIT 10;

这样 MySQL 可以从索引位置继续往后查,效率高很多。但它适合连续翻页,不适合随机跳页。

2. 先查 id 再回表

如果必须深分页,可以先用覆盖索引查 id:

SELECT idFROM tb_skuORDER BY create_timeLIMIT 200000, 10;

再根据 id 回表查详情。也可以写成 JOIN:

SELECT s.*FROM tb_sku sJOIN (  SELECT id  FROM tb_sku  ORDER BY create_time  LIMIT 200000, 10) t ON s.id = t.id;

这样至少避免一开始就搬运完整行数据。

九、表结构优化:大表和宽表要拆

如果单表数据达到千万级,查询压力可能明显增加。但不要一上来就分库分表,先看索引和 SQL 是否还能优化。

1. 垂直拆分宽表

如果一张表字段很多,可以按访问频率拆。比如:

user(id, name, phone, a vatar, description, remark, ext_json)

可以拆成:

user(id, name, phone)user_profile(user_id, a vatar, description, remark, ext_json)

高频字段放主表,低频大字段放扩展表,这样能减少单行大小,提高缓存命中率。

2. 冷热数据分离

订单表常见做法是按时间冷热分离:最近 3 个月订单放热表,历史订单放冷表,普通查询只查热表,可以降低高频查询的数据规模。

3. 分库分表

当单库或单表成为瓶颈时,再考虑分库分表。常见方式:

方式解决问题
垂直分库按业务拆库,降低单库压力
垂直分表拆宽表,减少单行体积
水平分库数据分散到多个库
水平分表大表拆成多个小表

分库分表会引入复杂度,比如分布式事务、跨库 JOIN、全局唯一 ID、分页排序、扩容迁移等。所以它是后手,不是起手式。

十、缓存优化:读多写少优先考虑

热点数据可以放 Redis,缓存的目标是减少数据库压力。常见读流程是旁路缓存:

应用先查缓存缓存命中,直接返回缓存未命中,查询数据库数据库返回后,写入缓存

写流程常见做法是:先更新数据库,再删除缓存。为什么不是先删缓存再更新数据库?因为并发下可能出现旧数据回写缓存。更推荐的做法是:先保证数据库成功,再删除缓存,让下一次读取重新加载新数据。

缓存也不是银弹,要考虑几个问题:

1. 缓存穿透

查询的数据根本不存在,请求每次都打到数据库。解决方式:缓存空值,或使用布隆过滤器。

2. 缓存击穿

某个热点 key 过期,大量请求同时打到数据库。解决方式:热点 key 不设置短过期,加互斥锁,或提前异步刷新。

3. 缓存雪崩

大量 key 同时过期,数据库瞬间被打爆。解决方式:过期时间加随机值,多级缓存,限流降级。

十一、架构优化:读写分离和分库分表

当 SQL 和索引已经优化过,但压力仍然大,就要看架构。

1. 主从复制

MySQL 主从复制大致流程:主库写入数据 → 主库记录 binlog → 从库拉取 binlog → 从库回放日志 → 从库得到相同数据。

2. 读写分离

读写分离的思路:写请求 → 主库,读请求 → 从库。这样可以提高读并发。但要注意主从延迟,比如用户刚下单,马上查订单,如果读从库可能查不到。这类强一致场景可以强制读主库。

3. 分库分表解决什么

分库主要解决单库资源瓶颈,分表主要解决单表数据量过大。简单理解:

单库扛不住 -> 分库单表太大   -> 分表字段太多   -> 垂直拆表读压力大   -> 读写分离 + 缓存

十二、慢查询和锁等待怎么定位

慢查询不一定都是索引问题。有时 SQL 本身不慢,是被锁卡住了。面试里可以把它拆成两类:

执行慢:SQL 扫描多、排序多、回表多等待慢:SQL 在等锁、等 IO、等连接

1. 开启慢查询日志

慢查询日志用来记录执行时间超过阈值的 SQL。常见参数:

SHOW VARIABLES LIKE 'slow_query_log';SHOW VARIABLES LIKE 'long_query_time';

临时开启可以这样:

SET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 1;

long_query_time = 1 表示超过 1 秒的 SQL 会被记录。生产环境一般要结合业务情况设置,不是越小越好,太小会产生大量日志。

2. 慢查询日志看什么

慢查询日志里常看:Query_time(SQL 总耗时)、Lock_time(等待锁的时间)、Rows_sent(返回行数)、Rows_examined(扫描行数)以及 SQL 原文。如果 Rows_examined 很大,说明扫描多,重点查索引和 SQL 写法。如果 Lock_time 很大,说明可能被锁阻塞,重点查事务和锁等待。

3. 用工具分析慢日志

慢查询日志很多时,不适合手动看。可以用:

mysqldumpslow -s t -t 10 slow.log

含义是按总耗时排序,取前 10 条。也可以用 pt-query-digest,它能聚合相似 SQL,看总耗时、平均耗时、执行次数和扫描行数。面试里说出这个工具,会显得更接近真实排查。

4. 当前正在执行什么 SQL

如果线上突然变慢,可以看当前连接:

SHOW FULL PROCESSLIST;

重点看 Command 是否是 QueryTime 是否很长,State 是否在等锁,Info 里具体 SQL 是什么。常见状态包括:

Sending dataWaiting for table metadata lockLockedCreating sort indexCopying to tmp table

其中 Waiting for table metadata lock 很典型,它表示在等元数据锁,也就是 MDL 锁。

5. 什么是 MDL 锁

MDL 是 metadata lock,元数据锁,它保护表结构不被并发破坏。比如一个事务正在查询表,另一个线程执行 ALTER TABLE user ADD COLUMN age INT;,这个 DDL 可能会等待 MDL 锁。更麻烦的是,后续新的查询也可能排队,于是一个 DDL 就拖慢一堆 SQL。所以线上执行 DDL 要特别小心。

6. 查 InnoDB 事务和锁等待

可以看 InnoDB 当前状态:

SHOW ENGINE INNODB STATUSG

重点看 LATEST DETECTED DEADLOCK(最近死锁信息)、TRANSACTIONS(当前事务)、是否有 lock wait、哪个事务持有锁、哪个事务在等待锁。MySQL 8.0 也可以查系统表:

SELECT * FROM performance_schema.data_locks;SELECT * FROM performance_schema.data_lock_waits;

这些表可以看到谁持有锁、谁在等锁。

7. 常见锁等待原因

慢查询里的锁等待,常见原因有:大事务长时间不提交;更新没有命中索引导致锁范围变大;间隙锁导致插入被阻塞;DDL 等 MDL 锁;事务里夹杂慢接口调用;批量更新一次改太多数据。比如:

UPDATE user SET status = 1 WHERE phone = '13800138000';

如果 phone 没索引,MySQL 可能扫描大量记录,在事务隔离级别和执行条件影响下,锁范围可能明显扩大。所以更新、删除语句的条件字段也要有索引。

8. 死锁怎么排查

死锁不是“数据库坏了”,它是两个事务互相等对方释放锁。例如:事务 A 锁住 id = 1,再等 id = 2;事务 B 锁住 id = 2,再等 id = 1,就会形成死锁。InnoDB 会自动检测死锁,并回滚其中一个事务。排查方式:SHOW ENGINE INNODB STATUSGLATEST DETECTED DEADLOCK。优化方式:固定访问顺序;缩短事务时间;减少一次事务影响的数据量;更新条件走索引;避免用户交互或远程调用放在事务里。

9. 面试怎么回答慢查询定位

可以这样说:

我会先看慢查询日志,通过 Query_time、Lock_time、Rows_examined 判断是执行慢还是等锁慢。如果 Rows_examined 很大,就用 EXPLAIN 看执行计划,重点看 type、key、rows、Extra,再优化索引和 SQL。如果 Lock_time 很大,就看 SHOW FULL PROCESSLIST,确认当前 SQL 是否在 Waiting for lock 或 metadata lock。然后用 SHOW ENGINE INNODB STATUS,或者 performance_schema.data_locks、data_lock_waits,定位哪个事务持有锁,哪个事务在等待。如果是死锁,看 LATEST DETECTED DEADLOCK,再从事务访问顺序、索引、事务范围几个方向优化。

慢查询排查不是只看 SQL,也要看它是不是在等锁。执行慢看 EXPLAIN,等待慢看锁和事务。

十三、面试回答模板

如果面试官问:一张表查询很慢,你有哪些解决方案? 可以这样回答:

我会先用慢查询日志定位慢 SQL,再用 EXPLAIN 分析执行计划。重点看 type、key、rows、Extra。如果是全表扫描,就看是否缺索引或索引失效。如果 rows 很大,就考虑减少扫描范围。如果有 Using filesort 或 Using temporary,就看 ORDER BY、GROUP BY 是否能通过索引优化。然后从几个层面处理:第一,优化索引,比如 WHERE、JOIN、ORDER BY、GROUP BY 字段建合适索引,多个字段高频组合查询就建联合索引,并遵循最左匹配原则。第二,避免索引失效,比如不要左模糊、不要对索引列使用函数或表达式,避免隐式类型转换,注意 OR 条件。第三,优化 SQL,避免 SELECT *,只查必要字段,尽量使用覆盖索引减少回表。JOIN 时让小结果集驱动大结果集,并保证被驱动表关联字段有索引。高频 JOIN 可以通过冗余字段减少关联。第四,优化分页,深分页不要直接 LIMIT 大 offset,可以改成基于 id 的位置分页,或者先查 id 再回表。第五,优化表结构,大表可以考虑冷热分离、水平拆表,宽表可以考虑垂直拆分。但拆表不是第一选择,要先看 SQL 和索引。第六,引入缓存,热点数据可以放 Redis,读请求使用旁路缓存,写请求可以先更新数据库再删除缓存,同时处理缓存穿透、击穿和雪崩。如果单机数据库压力仍然大,再考虑主从复制、读写分离、分库分表等架构方案。

最后可以补一句:

MySQL 调优不是只会加索引,而是先定位瓶颈,再分层优化。核心是减少扫描行数、减少回表、减少排序和临时表,并降低数据库整体压力。

十四、复习速记版

最后给你一版背诵用口诀:

先定位:慢日志 + EXPLAIN看计划:type、key、rows、Extra查索引:缺不缺、准不准、失没失效改 SQL:少查列、少回表、少 JOIN治分页:避开深 offset拆结构:大表拆、宽表拆、冷热分加缓存:热点进 Redis上架构:主从、读写分离、分库分表

再记住这几个判断:

key 为 NULL        -> 没用索引rows 很大          -> 扫描多type = ALL         -> 全表扫描Using filesort     -> 额外排序Using temporary    -> 用了临时表Using index        -> 覆盖索引,好事

总结

来源:https://www.jb51.net/database/3666772p8.htm
上一篇如何更改PostgreSQL数据库数据存储位置的详细步骤 下一篇Navicat 16跨平台全局快捷键映射设置指南
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
金仓数据库逻辑备份实战:全库导出与模式替换全流程
数据库 · 2026-07-03

金仓数据库逻辑备份实战:全库导出与模式替换全流程

在长期的运维实践中,我越来越体会到,备份就像一份保险——平时看似无用,但关键时刻却是唯一的救命稻草。逻辑备份看似简单,可真正执行恢复时,各种陷阱接连浮现:表名大小写不一致、Schema 未正确切换、Owner 属性未同步修改……任何一个环节处理不当,最终恢复出的数据库就会与预期相去甚远。 本文将深入

金仓数据库sys_rman物理备份全流程演练与误覆盖恢复
数据库 · 2026-07-03

金仓数据库sys_rman物理备份全流程演练与误覆盖恢复

干运维这行,逻辑备份和物理备份我都接触过,但说句实在话,真正能在生产环境里扛住事儿的,还得是物理备份。逻辑备份导出的是 SQL 语句,数据量一大,那速度慢得让人抓狂,而且最关键的是,它没法做时间点恢复。物理备份不一样,它直接拷贝数据文件,再配上 WAL 归档日志,想恢复到过去哪一秒都行,这是它最硬核

Windows下将MySQL注册为系统自启服务教程
数据库 · 2026-07-03

Windows下将MySQL注册为系统自启服务教程

先说一个关键前提:务必以管理员身份运行终端,否则 mysqld --install 这条命令几乎不可能成功。问题不在于命令写错,而是 Windows 系统的用户账户控制(UAC)机制会在中途拦截——在普通 CMD 或 PowerShell 窗口执行这条命令,要么直接提示 Access is deni

Mac版Navicat中快速对比两个数据库的表结构异同
数据库 · 2026-07-03

Mac版Navicat中快速对比两个数据库的表结构异同

直接说结论:Mac 版 Navicat 和 Windows 版在表结构比对逻辑上完全一致。但默认配置下,它确实无法承受“全库一键比对上万张表”的压力。要想避免卡死、内存溢出、进度条永远停在 0%,你必须手动将表分批处理,或者利用前缀过滤来控制扫描范围。 为什么 Mac 上点击「结构同步」后界面会卡住

MySQL中UNION操作推荐用UNION ALL的原因
数据库 · 2026-07-03

MySQL中UNION操作推荐用UNION ALL的原因

MySQL中UNION与UNION ALL性能对比:别再被“保险”迷惑,差距远超预期 先给出核心结论:UNION ALL 的性能通常比 UNION 高出不止一个数量级。原因在于,UNION 在合并结果集后会自动触发去重操作,这往往伴随着隐式排序,进而产生临时表和文件排序。而 UNION ALL 则直