mysql集合查询与索引有什么关系_mysql性能基础解析

1次阅读

UNION/UNION ALL 本身不使用索引,性能取决于各子查询是否有效利用索引;需为每个子查询的 WHERE、JOIN、ORDER BY 字段单独建索引,并避免外层 ORDER BY 导致索引失效。

mysql 集合查询与索引有什么关系_mysql 性能基础解析

集合查询(UNION/UNION ALL)本身不直接使用索引,但子查询是否走索引决定整体性能

MySQL 的 UNIONUNION ALL 是对多个 SELECT 结果集做合并操作,它本身不“走索引”,真正影响性能的是每个参与合并的子查询是否能有效利用索引。如果子查询写了 WHEREORDER BYJOIN,而对应字段没建索引,那整个 UNION 就会慢得明显——因为每个子查询都在全表扫描。

  • 子查询中用了 WHERE user_id = 123,但 user_id 没索引 → 全表扫两次,再合并,代价翻倍
  • UNION ALLUNION 快,因为它跳过去重逻辑;但去重本身不走索引,是内存 / 临时表排序完成的
  • 如果子查询结果集很大,MySQL 可能用 Using temporary; Using filesort,这时即使子查询走了索引,合并阶段仍可能成为瓶颈

多表 UNION 场景下,索引要分别建在各子查询的过滤 / 连接字段上

比如你写:

SELECT id, name FROM users WHERE status = 'active'   UNION ALL   SELECT id, name FROM admins WHERE role = 'super'

,这两个表结构不同、数据独立,那就得各自优化:在 users(status)admins(role) 上分别建索引。别指望一个索引跨表生效。

  • 不要试图给 UNION 后的结果加索引——结果集是虚拟的,不能建索引
  • 若子查询含 JOIN,比如 SELECT u.name FROM users u JOIN orders o ON u.id = o.user_id,则 orders(user_id) 必须有索引,否则 JOIN 退化为嵌套循环
  • 字段类型要一致:如果 users.idBIGINT,而 admins.idINTUNION 隐式转换,可能导致索引失效

ORDER BY + LIMIT 放在 UNION 外层时,索引大概率失效

这是高频踩坑点。例如:

(SELECT id, created_at FROM log_a WHERE type = 'error')   UNION ALL   (SELECT id, created_at FROM log_b WHERE type = 'error')   ORDER BY created_at DESC LIMIT 10

,MySQL 会先把两个子查询结果全部取出、合并、排序、再截断——哪怕 created_at 有索引,也用不上外层排序。

  • 解决方案:把 ORDER BY …… LIMIT 下推到每个子查询里(前提是语义允许),比如:
    (SELECT id, created_at FROM log_a WHERE type = 'error' ORDER BY created_at DESC LIMIT 10)   UNION ALL   (SELECT id, created_at FROM log_b WHERE type = 'error' ORDER BY created_at DESC LIMIT 10)   ORDER BY created_at DESC LIMIT 10
  • 注意:下推后需在外层再 ORDER BY …… LIMIT,否则无法保证全局 Top 10
  • 如果子查询本身无过滤条件(如纯 SELECT * FROM t),加索引也没用——全表扫完才排序

用 EXPLAIN 验证每个子查询是否真的用了索引

别只看最终 SQL 是否“跑出来”,要用 EXPLAIN 分别检查每个子查询。MySQL 8.0+ 支持 EXPLAIN FORMAT=TREE,能看清执行计划树;但更简单的是把 UNION 拆开,单独对每个 SELECT 执行 EXPLAIN

  • 关键看 type 列:要是 ALLindex,基本没走有效索引;refrangeconst 才算靠谱
  • 注意 key 列是否显示实际使用的索引名;key_len 能帮你判断是否用了联合索引的前缀
  • 如果子查询用了 ORLIKE '%abc'、函数包裹字段(如 YEAR(created_at)),索引大概率已失效——这些规则在子查询里同样适用

索引不是贴在 UNION 上的膏药,而是长在每个子查询的 WHERE、JOIN、ORDER BY 字段上的肌肉。漏掉任何一个子查询的索引,整条 UNION 就可能拖着腿跑。

text=ZqhQzanResources