多模数据库选型指南:从“多库拼装”到“一库多能”的架构演进

举报
这个DBA有点耶 发表于 2026/08/03 17:38:07 2026/08/03
【摘要】 传统数据架构正在被“多库拼装”模式压垮——关系型数据用MySQL、文档数据用MongoDB、时序数据用InfluxDB、向量数据用Milvus、图数据用Neo4j。一套完整的数据体系需要维护四五套数据库,多模数据库正是为解决这个问题而生——一套数据库内核原生支持关系、文档、图、时序、向量等多种数据模型。本文从多模数据库的概念出发,从架构、适用场景、生态兼容三个维度提供选型框架。

大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

前几周我们花了大量时间讲EXPLAIN——type怎么读、rows怎么理解、filtered怎么看、Extra里有什么。但有一个问题始终没回答:优化器凭什么这么选?

你肯定遇到过这种情况:明明有合适的索引,优化器却选了全表扫描;明明A计划更快,优化器却选了B计划。这时候你可能会骂优化器“笨”,但其实它只是做了一个“基于现有信息的最优判断”——而它依赖的“现有信息”,就是统计信息成本模型(Cost Model)

如果统计信息不准,或者成本模型的计算逻辑跟你预想的不一样,优化器的判断就会“跑偏”。今天我们把优化器的“算账逻辑”彻底拆开讲一遍。

一、成本模型是什么?——优化器不是“猜”,是“算”

数据库优化器是基于代价(Cost-Based) 的。它不会凭感觉选执行计划,而是会计算每种可能的执行方式的“代价”,然后选代价最小的那个。

这个“代价”不是时间,而是抽象的“资源开销单位”。主要由三部分构成:

成本类型 含义 说明
IO_cost 读写数据页的成本 从磁盘读取数据页到内存的代价,通常是成本的大头
CPU_cost 处理行数的成本 在内存中处理行数据的代价,比如比较、聚合、排序
memory_cost 临时内存使用成本 使用临时表或排序缓冲区的代价

简单说:优化器会把每个可能的执行计划换算成一个数字——cost,然后选cost最小的那个

那优化器是怎么算出这些cost的?靠统计信息。表有多少行、每列有多少个不同值、数据分布如何——这些信息决定了优化器估算“要读多少页、要处理多少行”。所以,统计信息是优化器的“眼睛” ,眼睛花了,算得再准也白搭。

二、怎么看到优化器的“账本”?——EXPLAIN FORMAT=JSON

传统的EXPLAIN只告诉你结果,不告诉你“账是怎么算的”。但MySQL 8.0提供了EXPLAIN FORMAT=JSON,能把优化器的成本估算完整地展示出来。

EXPLAIN FORMAT=JSON 
SELECT * FROM orders WHERE user_id = 12345 AND order_date > '2026-01-01';

输出的JSON中,最核心的部分是cost_info

"cost_info": {
  "read_cost": "1500.25",
  "eval_cost": "500.00",
  "prefix_cost": "2000.25",
  "data_read_per_join": "10M"
}

字段解读:

字段 含义
read_cost 读取数据的IO成本(读页次数)
eval_cost 评估和处理行的CPU成本
prefix_cost 当前表在JOIN顺序中的累计成本
data_read_per_join 预估读取的数据量大小

注意cost是优化器基于统计信息估算的相对代价,单位是“等价随机I/O次数”,不是真实执行耗时。它不反映CPU、内存、锁等待等运行时开销。但它的相对大小告诉我们优化器为什么选了A没选B。

三、更进一步:OPTIMIZER_TRACE——看优化器的“思考过程”

EXPLAIN FORMAT=JSON只展示了最终选中的计划的成本,但看不到优化器放弃了哪些计划、为什么放弃

这就是OPTIMIZER_TRACE的价值——它能完整记录优化器从接收SQL到选定执行计划的每一步决策:候选计划评估、规则应用、索引选择、成本对比,全部以JSON格式呈现。

使用方法:

-- 1. 开启跟踪
SET SESSION optimizer_trace = "enabled=on";
SET end_markers_in_json = ON;

-- 2. 执行要分析的SQL
SELECT * FROM orders WHERE user_id = 12345 AND order_date > '2026-01-01';

-- 3. 查看跟踪结果
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G

-- 4. 关闭
SET SESSION optimizer_trace = "enabled=off";

OPTIMIZER_TRACE的输出中,重点关注rows_estimation部分——它会列出优化器为每个候选索引计算的costrows,以及最终为什么选了某个计划。如果优化器选了一个看起来不合理的计划,这里通常会告诉你原因:可能是统计信息过旧导致rows估算偏差太大,可能是某个系统变量影响了成本权重计算。

四、真实案例:优化器“算错账”的根因排查

某电商系统,订单表orders有1000万行,(user_id, order_date)上有复合索引。业务SQL:

SELECT * FROM orders WHERE user_id = 12345 AND order_date > '2026-01-01';

正常情况下走复合索引,扫描几百行就返回。但某天突然变慢,执行计划显示type=ALL全表扫描。

OPTIMIZER_TRACE查看后发现,优化器估算user_id=12345会返回50万行(实际只有200行)。因为统计信息过旧,优化器认为“走索引回表50万次的IO成本,大于全表扫描1000万行的顺序读成本”,所以选了全表扫描。

执行ANALYZE TABLE orders更新统计信息后,优化器重新估算user_id=12345只返回200行,走复合索引的cost远低于全表扫描,查询从5秒降到了0.05秒。

关键认知:优化器不是“笨”,是“看错了”——它基于错误的统计信息做出了在当时看起来最优的决策。

五、成本模型的局限与注意事项

  1. cost是估算值,不是实际值EXPLAIN FORMAT=JSON中的cost是基于统计信息的估算,不是真实执行成本。验证优化效果应该用EXPLAIN ANALYZE获取实际执行数据。
  2. 统计信息的质量决定cost的准确度:如果统计信息过旧,cost估算可能偏差巨大。定期执行ANALYZE TABLE是保证优化器决策质量的基础。
  3. 系统变量会影响成本计算eq_range_index_dive_limitrange_optimizer_max_mem_size等参数会直接影响优化器的成本估算逻辑。
  4. IO_cost通常占大头:在磁盘表场景下,IO_cost通常是成本的主要组成部分。这就是为什么减少数据页读取(走索引、缩小扫描范围)是优化SQL最有效的手段。

六、总结

工具 能看到什么 解决什么问题
EXPLAIN 最终选的执行计划 知道“选了谁”
EXPLAIN FORMAT=JSON 最终计划的成本估算 知道“选了谁、花了多少钱”
OPTIMIZER_TRACE 完整的决策过程 知道“为什么选它、为什么没选另一个”

执行计划是优化器的“决策结果”,统计信息是优化器的“决策依据”,成本模型是优化器的“决策算法”。这三者形成一个完整的决策链:

统计信息 → 成本估算 → 执行计划

如果执行计划看起来不合理,不要急着骂优化器“笨”。先检查统计信息是否准确——大概率是优化器“看错了”,而不是“算错了”。学会用EXPLAIN FORMAT=JSONOPTIMIZER_TRACE看到优化器的“账本”和“思考过程”,你就能从“看懂EXPLAIN”升级到“理解优化器为什么这么选”。

小耶在手,SQL 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。