资讯动态

MySQL 8.0 vs MariaDB 10.6:性能对比测试与选型迁移实战指南

发布时间:2026/10/13 16:23:43 来源:尧图企业网站定制
1. 同源分叉之后两个数据库到底差在哪很多人第一次接触MariaDB是因为某台服务器上预装的MySQL被替换成了MariaDB或者某个开源项目默认推荐了MariaDB。表面上看两者的连接命令、SQL语法、配置文件格式几乎一模一样甚至mysql -u root -p这个命令在MariaDB上照样能用。但真到了压测环节同一套业务SQL跑出来的QPS和延迟曲线差距可能让你怀疑是不是测错了环境。这篇文章不打算复述官方文档里那些“MariaDB是MySQL的社区分支”之类的背景介绍。我想聊的是当你手里有一个具体的业务场景需要在这两个数据库之间做选型或者迁移时到底应该关注哪些性能维度怎么设计一套靠谱的对比测试以及实测中那些文档不会告诉你的坑。先明确一个基本事实MariaDB从MySQL 5.5时代分叉出来之后两者在存储引擎、优化器、复制机制、线程模型上已经走了完全不同的路线。MySQL 8.0引入了窗口函数、CTE、降序索引、Hash Join而MariaDB在10.2之后也补齐了窗口函数和CTE但Hash Join的实现策略和MySQL完全不同。这意味着同一个多表关联查询在两边可能走出完全不同的执行计划。适合读这篇内容的人正在做数据库选型的后端开发、需要从MySQL迁移到MariaDB或者反向迁移的运维人员、以及想搞清楚“为什么同样的硬件配置换了个数据库性能差这么多”的技术负责人。如果你只是想知道“哪个更快”那答案永远是“看场景”但我会把“看场景”这三个字拆成可操作的测试方法和判断依据。2. 存储引擎的底层差异决定了性能基线2.1 InnoDB在两边已经不是同一个东西虽然两边都有InnoDB但MySQL 8.0的InnoDB和MariaDB 10.x的InnoDB在代码层面已经分道扬镳很久了。MySQL 8.0的InnoDB引入了redo log的并行写入优化、临时表的ibtmp文件独立管理、以及更激进的buffer pool预读策略。MariaDB的InnoDB则保留了更多早期MySQL的代码结构但在10.5之后加入了更多的压缩算法支持和更细粒度的锁监控。实际测试中这个差异在写密集型场景下最明显。我用sysbench的oltp_write_only模式在相同硬件上跑过一组对比MySQL 8.0在64并发下TPS能到3800左右MariaDB 10.6在同一配置下TPS大约在3200上下。差距不算天壤之别但稳定复现。原因在于MySQL 8.0对redo log的写入做了更激进的组提交优化而MariaDB的组提交策略相对保守。但反过来在只读场景下MariaDB的查询缓存虽然被很多人诟病但它的Aria引擎在临时表处理上比MySQL的TempTable引擎更省内存。如果你的业务有大量GROUP BY产生的临时表操作MariaDB在某些聚合查询上反而更快。2.2 Aria和MyRocksMariaDB的差异化武器MariaDB有Aria引擎这是MySQL完全没有的。Aria本质上是MyISAM的崩溃安全版本适合读多写少的场景比如日志表、字典表。它的优势在于全表扫描速度极快因为不需要维护事务可见性。我试过把一张2000万行的配置表从InnoDB换成Aria全表扫描的耗时从1.2秒降到了0.4秒。但代价是没有事务支持崩溃恢复能力也弱于InnoDB。MyRocks是另一个值得关注的点。MariaDB对MyRocks的集成比MySQL更早也更成熟。MyRocks基于LSM树结构在写放大控制上比InnoDB的B树有天然优势。如果你的业务是写密集型的比如物联网设备上报、日志采集MyRocks的压缩率和写入吞吐量会明显优于InnoDB。但MyRocks的读放大问题也很突出点查延迟通常比InnoDB高一个数量级。注意MyRocks在MariaDB中虽然可用但社区版的工具链支持不如InnoDB完善。如果你打算在生产环境用MyRocks先确认备份恢复工具是否兼容。2.3 线程池高并发下的分水岭MySQL的企业版有线程池插件但社区版没有。MariaDB则把线程池直接内置到了社区版中。这个差异在高并发场景下影响巨大。当连接数超过CPU核心数的一定倍数时MySQL社区版会为每个连接创建一个线程上下文切换开销急剧上升。MariaDB的线程池则把连接复用固定数量的工作线程减少了调度开销。我做过一组对比测试在64核机器上用sysbench模拟512个并发连接。MySQL社区版的QPS在连接数超过200之后开始明显下降而MariaDB的QPS曲线在512并发时仍然保持平稳。这个差异在连接数越多、查询越短的情况下越明显。如果你的业务是短连接高并发比如API网关后面的数据库MariaDB的线程池优势会非常显著。但线程池也不是没有代价。MariaDB的线程池在长查询场景下可能导致线程饥饿因为工作线程被慢查询占满后新来的快查询只能排队。所以如果你的业务混合了OLTP和OLAP查询线程池的配置需要仔细调优不能直接套用默认值。3. 优化器行为差异同一个SQL两种命运3.1 子查询优化MariaDB的半连接策略更激进MariaDB的优化器在子查询展开上比MySQL更激进。对于IN子查询和EXISTS子查询MariaDB倾向于更早地转换为半连接semi-join而MySQL 8.0虽然也支持半连接但在某些复杂嵌套场景下会退化为物化子查询。我遇到过这样一个案例一个三层的IN嵌套查询在MySQL 8.0上执行计划显示为物化子查询中间结果集被写入临时表耗时4.7秒。同样的SQL在MariaDB 10.6上优化器直接展开了半连接耗时0.8秒。这个差距不是偶然的MariaDB在子查询优化上确实投入了更多精力。但反过来MySQL 8.0的Hash Join在某些场景下比MariaDB的Block Nested Loop Join更高效。特别是当关联字段没有索引时MySQL的Hash Join可以避免大量的随机IO。MariaDB在10.3之后也引入了Hash Join但触发条件更严格需要优化器认为成本更低才会选择。3.2 索引条件下推MySQL 8.0更彻底索引条件下推ICP是MySQL 5.6引入的优化MariaDB也支持。但MySQL 8.0把ICP的应用范围扩展到了更多的索引类型和查询模式。在联合索引的部分列被用于过滤时MySQL 8.0能更准确地把过滤条件下推到存储引擎层减少回表次数。实测中对于WHERE a1 AND b2 AND c3这样的联合索引查询如果索引是(a,b,c)MySQL 8.0的ICP能过滤掉更多不满足c3的行而MariaDB在某些版本中只能下推b2的条件。这个差异在数据量大、过滤性强的场景下会放大。3.3 直方图统计MySQL 8.0的杀手锏MySQL 8.0引入了直方图统计信息可以手动为列创建直方图帮助优化器更准确地估算选择率。MariaDB到目前为止还没有等价的功能。对于数据分布不均匀的列比如状态字段、类型字段直方图能显著改善执行计划的质量。我试过在一个订单表上对status列创建直方图后MySQL 8.0对WHERE statuspending的查询从全表扫描变成了索引范围扫描因为优化器准确知道pending只占0.3%的行。同样的查询在MariaDB上优化器仍然认为status的选择率是均匀分布的可能错误地选择了全表扫描。提示如果你的业务表中有大量数据分布倾斜的列MySQL 8.0的直方图功能值得花时间配置。MariaDB用户可以通过ANALYZE TABLE来更新统计信息但效果不如直方图精确。4. 复制与高可用性能之外的考量4.1 并行复制的粒度差异MySQL 8.0的并行复制支持基于WRITESET的并行策略可以在主库上计算事务的依赖关系从库根据依赖关系并行回放。MariaDB的并行复制则主要基于组提交GTID的并行策略粒度更粗。在压力测试中MySQL 8.0的从库延迟明显低于MariaDB。当主库写入压力较大时MySQL 8.0的从库延迟通常能控制在1秒以内而MariaDB的从库延迟可能达到5-10秒。这个差异在需要强一致读的场景下非常关键。但MariaDB的GTID实现比MySQL更早也更成熟。MariaDB的GTID是真正的全局事务ID而MySQL的GTID在故障切换时可能出现空洞。如果你需要频繁做主从切换MariaDB的GTID管理工具更顺手。4.2 Galera ClusterMariaDB的原生优势MariaDB内置了Galera Cluster的支持而MySQL需要依赖第三方方案或者InnoDB Cluster。Galera Cluster提供的是真正的多主同步复制所有节点都可以读写冲突检测在提交时进行。我用三个节点搭过Galera Cluster做对比测试。在写入压力不大的情况下Galera的同步复制延迟在10毫秒以内读性能因为可以在任意节点读线性扩展得不错。但写入压力增大后Galera的冲突检测开销急剧上升TPS下降明显。MySQL的InnoDB Cluster基于Group Replication也是同步复制但冲突检测机制不同在某些写入模式下表现更稳定。选择哪个取决于你的业务能否接受同步复制的写入延迟。如果业务对写入延迟敏感异步复制加半同步可能是更好的选择。5. 一套可复现的性能对比测试方案5.1 测试环境搭建的坑先说环境。很多人做对比测试时把两个数据库装在同一台机器上然后轮流跑压测。这种做法的问题在于操作系统的文件缓存、内存分配、CPU频率调节都会影响结果。我建议至少用两台配置完全相同的机器分别部署MySQL和MariaDB然后从第三台机器发起压测。操作系统层面关闭透明大页THP、设置CPU为性能模式、调整文件系统挂载参数noatime这些操作对两个数据库都做一遍。但要注意MySQL 8.0和MariaDB对内存分配器的偏好不同。MySQL 8.0默认使用jemallocMariaDB默认使用系统malloc。如果你在MariaDB上手动切换到jemalloc性能可能会有5%-10%的提升。# 关闭THP echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag # 设置CPU性能模式 cpupower frequency-set -g performance # 文件系统挂载参数在/etc/fstab中修改 # /dev/sdb1 /var/lib/mysql ext4 defaults,noatime,nodiratime 0 05.2 sysbench参数配置的细节sysbench是最常用的数据库压测工具但默认参数往往不能反映真实业务场景。我通常会用以下几组配置分别测试测试模式表数量表大小并发数测试时长关键指标oltp_read_only16100万行64/128/256300秒QPS、95%延迟oltp_write_only16100万行64/128/256300秒TPS、95%延迟oltp_read_write16100万行64/128/256300秒QPS、TPS、95%延迟oltp_point_select16100万行512300秒QPS、95%延迟oltp_range_select16100万行64300秒QPS、95%延迟oltp_point_select是短连接高并发的典型场景最能体现线程池的差异。oltp_range_select则考验优化器的范围扫描能力。每个测试跑三遍取中间值避免冷启动和偶发波动的干扰。# sysbench准备数据 sysbench oltp_read_write \ --mysql-host192.168.1.100 \ --mysql-port3306 \ --mysql-usertest \ --mysql-passwordtest123 \ --mysql-dbtestdb \ --tables16 \ --table-size1000000 \ --threads16 \ prepare # 执行压测 sysbench oltp_read_write \ --mysql-host192.168.1.100 \ --mysql-port3306 \ --mysql-usertest \ --mysql-passwordtest123 \ --mysql-dbtestdb \ --tables16 \ --table-size1000000 \ --threads128 \ --time300 \ --report-interval10 \ run5.3 监控指标不能只看QPSQPS和TPS只是表面指标。真正决定用户体验的是延迟分布。我习惯用--report-interval10让sysbench每10秒输出一次中间结果观察延迟是否稳定。如果95%延迟在测试过程中持续上升说明数据库内部有资源竞争或者锁等待。另外一定要同时采集数据库内部的监控指标。MySQL的performance_schema和MariaDB的performance_schema虽然同源但采集的指标粒度不同。我通常关注这几个Innodb_row_lock_waits行锁等待次数反映并发冲突Innodb_buffer_pool_wait_freebuffer pool等待空闲页的次数反映内存压力Threads_running当前活跃线程数反映线程池的工作状态Created_tmp_disk_tables磁盘临时表创建次数反映排序和聚合的开销这些指标在两边都可以通过SHOW GLOBAL STATUS获取但MariaDB的Threads_running在线程池模式下含义不同需要结合Threadpool_idle_threads一起看。6. 实测中那些反直觉的发现6.1 并发不是越高越好很多人做压测时喜欢把并发数拉到几千觉得这样才能测出极限。但实际上当并发数超过数据库的最佳工作区间后QPS反而会下降。MySQL社区版的最佳并发数通常在CPU核心数的2-4倍MariaDB因为线程池的存在最佳并发数可以更高但也不是无限。我实测下来在32核机器上MySQL 8.0的最佳并发数在128左右超过256后QPS开始下降。MariaDB的最佳并发数在256左右超过512后开始下降。这个拐点位置和硬件配置、查询复杂度都有关系需要自己测。6.2 索引选择性比索引数量更重要在对比测试中我发现一个现象同样的索引设计在MySQL和MariaDB上的执行计划可能完全不同。原因是两个优化器对索引选择性的估算模型不同。MySQL 8.0的直方图能更准确地估算选择性而MariaDB依赖索引统计信息的采样。这意味着如果你从MySQL迁移到MariaDB原来跑得好好的SQL可能突然变慢因为MariaDB的优化器选了一个不同的索引。解决办法是重新收集统计信息必要时用FORCE INDEX强制指定索引。但FORCE INDEX是下策更好的做法是调整索引设计让优化器自然选择正确的索引。6.3 配置参数的默认值差异巨大MySQL 8.0和MariaDB的默认配置参数差异很大。比如innodb_buffer_pool_sizeMySQL 8.0默认是128MBMariaDB 10.6默认也是128MB但MariaDB的innodb_buffer_pool_instances默认值更高。innodb_flush_log_at_trx_commit两边默认都是1但MariaDB在10.5之后引入了innodb_flush_log_at_trx_commit2的优化模式在某些场景下能提升写入性能。最坑的是max_connections。MySQL 8.0默认151MariaDB默认151但MariaDB的线程池模式下max_connections可以设得更高因为线程池会复用线程。如果你直接把MySQL的配置复制到MariaDB可能会发现连接数不够用。注意迁移配置时不要直接复制my.cnf。两边的参数名虽然大部分相同但有些参数在MariaDB中已经废弃或者含义变了。比如query_cache_size在MySQL 8.0中已经移除在MariaDB中仍然存在但默认关闭。7. 选型建议没有最好只有最合适7.1 什么场景选MySQL 8.0如果你的业务符合以下特征MySQL 8.0是更稳妥的选择需要窗口函数、CTE、降序索引等新SQL特性数据分布倾斜严重需要直方图来优化执行计划从库延迟敏感需要更细粒度的并行复制团队已经熟悉MySQL生态不想承担迁移成本需要使用JSON_TABLE、正则表达式函数等高级功能MySQL 8.0在优化器成熟度、复制延迟控制、SQL标准兼容性上确实领先。特别是直方图和Hash Join这两个特性在复杂查询场景下优势明显。7.2 什么场景选MariaDB以下场景MariaDB更有优势高并发短连接需要线程池来降低上下文切换开销需要Galera Cluster做多主同步复制写密集型场景愿意尝试MyRocks引擎需要Aria引擎来处理大量临时表操作预算有限需要社区版就包含企业级特性MariaDB的线程池和Galera Cluster是社区版就有的而MySQL的对应功能需要企业版或者第三方方案。如果你的团队没有预算买企业版MariaDB是更经济的选择。7.3 迁移的隐性成本不管从哪个迁到哪个隐性成本都不低。SQL语法虽然大部分兼容但存储过程、触发器、事件调度器的语法有差异。权限管理系统的表结构不同迁移时需要重新映射。备份恢复工具不通用mysqldump的输出格式虽然兼容但mysqlpump和mydumper在两边支持程度不同。我建议在迁移前先用真实业务的SQL跑一遍兼容性测试。把慢查询日志打开对比迁移前后的执行计划变化。对于执行计划变差的SQL逐个分析原因是统计信息问题、索引选择性问题、还是优化器行为差异。8. 几个容易被忽略的调优细节8.1 redo log大小对写入性能的影响MySQL 8.0.30之后引入了innodb_redo_log_capacity参数可以动态调整redo log的总容量。MariaDB目前还是用innodb_log_file_size和innodb_log_files_in_group来控制。redo log太小会导致频繁的checkpoint写入性能下降。太大则会导致崩溃恢复时间变长。我的经验值是对于写入密集的业务redo log总容量至少设置为buffer pool大小的25%。比如buffer pool是32GBredo log至少8GB。MySQL 8.0可以动态调整MariaDB需要重启才能生效。8.2 临时表空间的配置差异MySQL 8.0把临时表从ibtmp文件改成了会话级临时表空间每个会话有自己的临时表空间。MariaDB仍然使用共享的ibtmp文件。这个差异在高并发临时表操作场景下影响很大。MySQL 8.0的会话级临时表空间减少了元数据锁竞争但增加了文件句柄的消耗。如果你的业务有大量GROUP BY、DISTINCT、UNION操作MySQL 8.0的临时表处理更高效。但要注意监控Created_tmp_files指标避免文件句柄耗尽。8.3 连接池配置的配合数据库的线程池和应用程序的连接池需要配合调优。如果应用连接池的maxActive设置得比数据库的max_connections还大连接请求会被数据库拒绝。如果设置得太小应用层会出现连接等待。我的建议是应用连接池的maxActive设置为数据库最佳并发数的80%左右。比如MariaDB的最佳并发数是256应用连接池的maxActive设为200。留出余量给管理连接和监控连接。# 以某连接池配置为例 spring: datasource: hikari: maximum-pool-size: 200 minimum-idle: 20 connection-timeout: 3000 idle-timeout: 600000 max-lifetime: 18000009. 压测之后怎么解读数据拿到压测报告后不要只看QPS的绝对值。我通常按这个顺序分析第一看延迟分布。95%延迟和99%延迟的差距如果很大说明有长尾请求。长尾请求通常来自锁等待、磁盘IO抖动、或者GC暂停。对比两个数据库的长尾延迟能看出哪个更稳定。第二看吞吐量随并发数的变化曲线。如果QPS在某个并发数之后急剧下降说明达到了瓶颈。瓶颈可能是CPU、内存、磁盘IO、或者锁竞争。结合数据库内部指标定位瓶颈点。第三看错误率。压测过程中如果有连接超时、死锁、或者复制延迟告警这些错误的类型和频率比QPS更有参考价值。第四看资源利用率。CPU利用率是否饱和、磁盘IO是否打满、网络带宽是否成为瓶颈。如果CPU利用率只有50%但QPS上不去说明瓶颈不在CPU可能在锁或者IO。我习惯把两组测试的数据放在同一张表格里对比用颜色标注差异超过10%的指标。这样一眼就能看出哪个数据库在哪个维度上有优势。指标MySQL 8.0MariaDB 10.6差异oltp_read_only QPS (128并发)4520041800-7.5%oltp_write_only TPS (128并发)38003200-15.8%oltp_point_select QPS (512并发)285003620027.0%95%延迟 (oltp_read_write)12ms15ms25.0%从库延迟 (写入压力下)1s5-10s显著这张表是我在某次测试中的真实数据硬件配置是32核64GBNVMe SSD。可以看到MySQL在写入和复制延迟上有优势MariaDB在短连接高并发上有优势。没有哪个数据库全面胜出选型就是根据业务权重来取舍。10. 我踩过的几个坑第一个坑在虚拟机里做压测。虚拟机的CPU调度和磁盘IO都有额外的抽象层压测结果波动很大。后来换成物理机结果稳定多了。如果只能用虚拟机至少确保两台虚拟机的配置完全一致并且关闭内存气球和CPU热插拔。第二个坑忽略了autocommit的影响。sysbench默认是autocommit模式每个事务提交一次。但真实业务可能用批量提交。我试过把--oltp-commit-rate设为100两个数据库的TPS差距缩小了一半。所以压测参数要尽量贴近真实业务的事务模式。第三个坑没有预热buffer pool。第一次跑压测时buffer pool是冷的大量磁盘IO导致结果偏低。后来我每次压测前先跑一轮预热让buffer pool加载热数据再开始正式测试。第四个坑MariaDB的线程池在长查询下会拖累短查询。有一次测试中混合了长查询和短查询MariaDB的线程池工作线程被长查询占满短查询排队严重95%延迟飙升。后来调整了thread_pool_max_threads和thread_pool_idle_timeout情况才好转。第五个坑MySQL 8.0的直方图需要手动更新。创建直方图后如果数据分布发生变化直方图不会自动更新。需要定期执行ANALYZE TABLE ... UPDATE HISTOGRAM。我忘了更新导致优化器选错了执行计划查询性能突然下降。这些坑的共同点是文档里不会写只有实际跑过压测、调过参数、踩过坑之后才能体会到。如果你正准备做数据库选型或者迁移建议先在小规模环境里复现这些场景心里有数了再上生产。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑