线上接口突然慢下来,第一眼看日志,数据库耗时只写着一行:
SQL cost=842ms, datasource=order-db, sql=select * from order_item where order_id = ?
这种日志我一般不会马上骂 MySQL,也不会马上吹 PostgreSQL。先看执行计划,再看连接池,再看团队是不是把一个简单查询写成了“数据库能力秀”。
面试里问:PostgreSQL 已经很强,为什么还要用 MySQL?
这个问题要是回答“因为 MySQL 简单、生态好”,只能算答到门口。真到项目里选型,数据库不是谁功能多谁赢,是谁更适合这套系统、这帮人、这堆历史包袱。
PostgreSQL 强,这个没什么好争的。
它的 SQL 标准支持更完整,复杂查询、窗口函数、CTE、JSON、数组、GIS 这些能力都很舒服。复杂报表、多维查询、偏分析的业务,用 PostgreSQL 经常能少绕很多弯子。很多场景下,PostgreSQL 的执行器、类型系统、扩展能力确实更像一个“数据库平台”。
但问题来了,业务系统不全是复杂查询。
大量 Java 后台系统,核心 SQL 长这样:
select id, status, pay_amount
from t_order
where user_id = ?
and create_time >= ?
order by id desc
limit 20;
再复杂一点,也就是:
update t_order
set status = ?, pay_time = now()
where order_no = ?
and status = 'WAIT_PAY';
这种 OLTP 场景,真正拼的不是数据库有没有高级类型,而是稳定、可预期、好排查、团队都能接住。
MySQL 的优势就在这里。
Java 生态里,MySQL 太常见了。Spring Boot、MyBatis、JPA、ShardingSphere、Canal、Debezium、各类 Druid/Hikari 监控,默认文档里十有八九先拿 MySQL 举例。出了问题,搜索报错、查执行计划、看慢 SQL、问 DBA,路径都很短。
比如慢 SQL 排查,MySQL 这套东西大家太熟了:
explain
select
id, status
from t_order
where user_id = 10086
order by create_time desc
limit 10;
看到 type=range、key=idx_user_time、rows=30,基本心里有数。
要是看到这个:
type=ALL
key=NULL
rows=780000
Extra=Using where; Using filesort
不用开会,先补索引:
create index idx_order_user_time
on t_order(user_id, create_time);
PostgreSQL 当然也能看执行计划,而且信息更多。但说实话,信息多不等于团队能用好。线上出故障的时候,不是比谁理论懂得多,是比谁能在十分钟内把问题收住。
还有一个很现实的点:历史系统。
很多公司不是今天从零开始选数据库。它可能十年前就用了 MySQL,表结构、分库分表、binlog 同步、数据订正脚本、运维备份、监控告警,全都围着 MySQL 长出来了。
你说 PostgreSQL 更强,没错。
但把一个跑了多年的订单库迁过去,不是改个 JDBC URL:
spring:
datasource:
url: jdbc:mysql://mysql-prod:3306/trade
username: app_trade
换成:
spring:
datasource:
url: jdbc:postgresql://pg-prod:5432/trade
就完事了?
别闹。
字段类型要核,SQL 方言要改,自增主键要处理,分页语法要扫,时间类型要测,事务隔离差异要压,线上回滚方案还得准备。尤其 Java 项目里那些散落在 XML 里的动态 SQL,平时看着安静,一迁库全出来咬人。
我见过最烦的一类 SQL,不是多复杂,而是这种:
<select id="listByIds" resultType="OrderDO">
select *
from t_order
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
foreach>
select>
这种在 MySQL 跑了很多年,大家默认没问题。迁库时一旦涉及批量大小、参数绑定、执行计划变化,就得重新测。数据库迁移最怕的不是“不能跑”,是“能跑,但偶尔慢”。
MySQL 还有一个非常实用的能力:主从复制和 binlog 生态。
很多 Java 系统做缓存更新、搜索同步、数据异构,都是靠 binlog 往外推。比如订单表变更后,同步到 ES:
MySQL binlog -> Canal -> MQ -> search-service -> Elasticsearch
这条链路太成熟了。出了问题也好查:
show master status;
show slave status\G;
延迟、位点、relay log、GTID,DBA 和后端都知道该看哪里。PostgreSQL 也有逻辑复制,也能做 CDC,但在不少团队里,MySQL 这套链路的熟练度就是更高。
选型的时候,我会把问题拆得更粗暴一点。
如果是交易、订单、账户、库存这种典型 OLTP,SQL 不复杂,写多读多,团队 MySQL 经验足,周边组件也都是 MySQL 生态,那我倾向 MySQL。
不是因为它更高级,而是因为它够用,且风险小。
如果是复杂权限查询、报表分析、地理位置、JSON 结构很多、需要更强 SQL 表达能力,或者项目本来就有 PostgreSQL DBA,那 PostgreSQL 很香。
但别拿 PostgreSQL 的强项去打 MySQL 的日常场景。
面试时可以这样答:
PostgreSQL 很强,但数据库选型不是单看功能上限。MySQL 在 Java Web 和互联网 OLTP 场景里生态更成熟,团队经验更普遍,运维、监控、分库分表、binlog 同步、故障排查链路都更短。大量业务只是简单增删改查,MySQL 的能力已经够用,而且稳定、成本低、迁移风险小。PostgreSQL 更适合复杂 SQL、扩展能力要求高、数据类型丰富的场景;MySQL 更适合团队协作成本敏感、链路成熟度要求高的常规业务系统。
最后补一句我自己的判断。
技术选型不要只看“谁更强”,要看“谁出事的时候你能不能救回来”。
线上凌晨两点,慢 SQL 打满连接池,业务还在催单。这个时候你最需要的,不是数据库功能表上多几个勾,而是团队有人能立刻看懂这条日志:
HikariPool-1 - Connection is not available, request timed out after 30000ms
然后知道下一步该查慢 SQL、查连接池、查锁等待,还是查主从延迟。
能救火的技术,才是真的适合生产。