SQL 事务隔离级别性能对比

1次阅读

read committed 比 serializable 快但弱一致性,适用于写入密集型业务;serializable 保证强一致但性能低,仅用于金融对账等场景,且需重试逻辑。

SQL 事务隔离级别性能对比

READ COMMITTED 比 SERIALIZABLE 快,但不是所有场景都适用

事务隔离级别本质是「一致性」和「并发性能」的权衡。READ COMMITTED 允许其他事务在当前事务执行期间修改并提交数据,因此不加范围锁、不阻塞读写,吞吐高;SERIALIZABLE 则通过加锁或快照序列化保证绝对一致,但容易触发锁等待甚至死锁,QPS 明显下降。

实操建议:

  • Web API 写入密集型业务(如订单创建)默认用 READ COMMITTED,避免长事务拖慢整体响应
  • 金融类对账、库存扣减等强一致性场景,才考虑 SERIALIZABLE,且必须配合重试逻辑
  • postgresqlSERIALIZABLE 是可串行化快照(SSI),比 mysql 的传统锁实现更轻量,但仍有约 5–10% 性能损耗
  • MySQL 默认 REPEATABLE READ 在某些 UPDATE 场景下会隐式升级为间隙锁,实际开销接近 SERIALIZABLE,需用 EXPLAIN 看执行计划确认

脏读、幻读、不可重复读到底在哪一级别出现

这些现象不是“会不会发生”,而是“数据库是否保证不发生”。不同级别只承诺屏蔽其中一部分,其余靠应用层兜底。

常见错误现象:

  • READ UNCOMMITTED:能看到未提交事务的数据,select 返回脏数据,生产环境禁用
  • READ COMMITTED:解决脏读,但同一事务中两次 SELECT 可能返回不同结果(不可重复读),INSERT 后再 SELECT 可能多出新行(幻读)
  • REPEATABLE READ(MySQL):解决脏读和不可重复读,但幻读仍存在(仅靠行锁无法拦截新插入)
  • SERIALIZABLE:理论上杜绝全部三类,但代价是锁表或全扫描级锁,SELECT 也可能被阻塞

PostgreSQL vs MySQL 隔离级别行为差异

名字一样,语义未必相同。尤其 REPEATABLE READ 在两者中完全不是一回事。

使用场景与参数差异:

  • PostgreSQL 的 REPEATABLE READ 实际等价于标准 SQL 的 SERIALIZABLE(SSI 实现),不会出现幻读,但可能因冲突自动回滚,报错:could not serialize access due to concurrent update
  • MySQL 的 REPEATABLE READ 基于 MVCC + 间隙锁,不自动回滚,但幻读真实存在——比如 SELECT ... for UPDATE 不锁新插入行,后续 INSERT 仍可成功
  • 连接字符串里设 isolation_level=serializable 在 SQLAlchemy 中对 PostgreSQL 有效,但在 MySQL 中只是降级为 REPEATABLE READ,不会真正串行化
  • 跨数据库迁移时,不能只改配置项名,必须重审业务逻辑是否依赖某一级别的具体行为

如何测出你真正在用哪个隔离级别

数据库客户端显示的级别,不等于当前事务生效的级别。很多 ORM 或连接池会在建连后执行 SET TRANSACTION ISOLATION LEVEL,但也可能被中间件覆盖或忽略。

实操建议:

  • MySQL 中查当前会话级别:SELECT @@transaction_isolation;查全局默认:SELECT @@global.transaction_isolation
  • PostgreSQL 中用:SHOW transaction_isolation,注意它反映的是当前事务开始时的设置,不是连接初始化值
  • 在事务内执行 SELECT pg_backend_pid(), now() 并另起一个会话观察锁状态,比看配置更可靠
  • ORM 如 djangoatomic(using='xxx', savepoint=True) 不改变隔离级别,只控制回滚点,别误以为它提升了隔离强度

真正影响性能的从来不是“选哪个级别”,而是你有没有意识到:同一张表上,SELECTUPDATE 在不同级别下加的锁类型、范围、持续时间完全不同。这点最容易被忽略。

text=ZqhQzanResources