PG系、Oracle、MySQL数据库在特定场景下结果差异分析

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 本文主要介绍以PolarDB O引擎、ADB PG为代表的PG系数据库在某种特定事务场景下,其事务结果与Oracle、MySQL不同的现象,并分析该现象出现的原因。

本文主要介绍以PolarDB O引擎、ADB PG为代表的PG系数据库在某种特定事务场景下,其事务结果与Oracle、MySQL不同的现象,并分析该现象出现的原因。

一、数据初始化

Create table test(id int,money int);
insert into testtable values(1,80);
insert into testtable values(1,90);
insert into testtable values(1,100);
insert into testtable values(1,110);
insert into testtable values(1,120);

二、测试过程

1)事务A显式开启事务执行,暂不提交:

delete  from testtable where id = 1;
insert into testtable values (1,100);
select * from testtable;

2)事务B自动提交执行:

delete  from testtable where id = 1;
insert into testtable values(2,110);
select * from testtable;

3)由于事务A未提交导致事务B delete等锁,间隔几秒后提交事务A,之后事务B自动提交完成

三、测试结果

PS:经过验证,事务B的Delete操作无论在事务A的insert操作前后发起,对最终事务结果无影响

Oracle(Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production)

MySQL (5.7.32-log)

ADBPG(PostgreSQL 9.4.24 (Greenplum Database 6.3.0 build dev) on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 6.5.1 20190307 (Alibaba 6.5.1-1 2.17), 64-bit compiled on Oct 25 2021 20:00:34)

PostgrelSQL(PostgreSQL 10.14)

PolarDB O引擎(PostgreSQL 11.9 (POLARDB Database Compatible with Oracle 11.9.18)

四、测试结论

该场景下MySQL处理逻辑和Oracle一致,PG系数据库均会出现数据冗余情况,类似Oracle业务场景做PG系替换有数据不一致风险,需要重点关注。

五、原因分析

  1. 分析原因前我们先介绍下事务型(TP)数据库常用的几种事务隔离级别:
  • Read Uncommitted:读未提交(脏读),一个事务可以读到另外一个事务未提交的数据,大多数关系型数据库不支持。
  • Read Committed:读已提交,一个事务可以读到其他事务已经提交的数据,大多数数据库的缺省模式。
  • Repeatable Read:可重复读,一个事务执行过程中访问的数据是一致的,也就是一个事务中多次读到的数据不会变化。
  • Serializable:序列化(串行化),事务串行化执行,避免不一致。代价很大,OLTP系统中很少使用。
  1. Oracle、MySQL、PG系事务数据库目前都是读已提交(read committed)的隔离级别。
  2. 其次再介绍下数据库的MVCC、当前读、快照读等概念:
  • MVCC:Multi-version Concurrency Control (多版本并发控制),维持一个数据的多个版本,使得读写操作没有冲突
  • 当前读:像select lock in share mode( 共享锁), select for update ; update, insert ,delete( 排他锁)这些操作都是一种当前读,为什么叫 当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁
  • 快照读:像 不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

基于上面的概念我们再来看Oracle/MySQL和PG系TP数据库在该事务场景下的差别时就可以作出如下的推测:

对于Oracle/MySQL结果只有事务B的新插入行:Oracle/MySQL的RC隔离级别下除了select操作都是当前读,因此当事务A对应行上X锁释放后,事务B重新获取X锁时发现行消失会重新索引扫描获取当前读状态,因而直接获取到事务A新插入的行并删除

从MySQL的官方文档我们也可以得到相应的佐证信息:

If you want to see the “freshest” state of the database, use either the READ COMMITTED isolation level or a locking read

原文如上,翻译过来就是如果始终希望获取数据的最新状态,建议使用Read Committed 的隔离级别或者使用带锁的读取操作(如select lock in share mode/delete隐式读/update隐式读等 );也就是MySQL/Oracle除了普通的select操作,其他操作时都会去获取数据的最新当前读状态

对于PG系结果同时含有事务A、B新插入的行:可能存在如下两种原因

  • Case1:PG内核逻辑可能是发现之前的行不存在时就判断事务不用执行直接提交了,不会去走重新索引扫描获取当前读状态,因此事务A新插入的那条数据会依旧存在,出现冗余。
  • Case2:PG内核在事务B发现行消失时也会重新索引扫描,但是PG系内核对于Delete的查询操作也使用了快照读,因此并不会读取到事务A 新插入的这行数据,因而事务B并不会删除该行数据,出现冗余

那么确切的原因什么,我们可以从PG的官方文档找到答案,如下图:

If the first updater commits, the second updater will ignore the row if the first updater deleted it, otherwise it will attempt to apply its operation to the updated version of the row.

前述这段英文是其中最关键的信息,简而言之就是如果事务A Delete了对应行,事务B提交时会直接忽略对应行,而不是重新获取当前读状态;而如果事务A Update了对应行,则此时事务B才会去重新获取当前读状态并基于该状态继续做更新操作。即我们推断的Case1是符合真实情况的

综上分析,PG系和Oracle/MySQL内核在Delete锁冲突时一点细微的处理逻辑差异,导致了在特定的事务场景下出现了数据不一致的情况。

六、参考文档

PostgreSQL官方文档:Read Committed Isolation Level

MySQL官方文档:Consistent Nonlocking Reads

一文读懂PostgreSQL事务隔离级别:链接

正确的理解MySQL的MVCC及实现原理:链接

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
10天前
|
Oracle 关系型数据库 Linux
【赵渝强老师】Oracle数据库配置助手:DBCA
Oracle数据库配置助手(DBCA)是用于创建和配置Oracle数据库的工具,支持图形界面和静默执行模式。本文介绍了使用DBCA在Linux环境下创建数据库的完整步骤,包括选择数据库操作类型、配置存储与网络选项、设置管理密码等,并提供了界面截图与视频讲解,帮助用户快速掌握数据库创建流程。
178 93
|
10天前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
44 3
|
10天前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(上)
最终建议:当前系统是完美的读密集型负载模型,优化重点应放在减少行读取量和提高数据定位效率。通过索引优化、分区策略和内存缓存,预期可降低30%的CPU负载,同时保持100%的缓冲池命中率。建议每百万次查询后刷新统计信息以持续优化
62 6
|
10天前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(中)
使用MYSQL Report分析数据库性能
57 1
|
22天前
|
SQL Oracle 关系型数据库
Oracle数据库创建表空间和索引的SQL语法示例
以上SQL语法提供了一种标准方式去组织Oracle数据库内部结构,并且通过合理使用可以显著改善查询速度及整体性能。需要注意,在实际应用过程当中应该根据具体业务需求、系统资源状况以及预期目标去合理规划并调整参数设置以达到最佳效果。
81 8
|
1月前
|
存储 关系型数据库 MySQL
深入理解MySQL索引类型及其应用场景分析。
通过以上介绍可以看出各类MySQL指标各自拥有明显利弊与最佳实践情墁,在实际业务处理过程中选择正确型号极其重要以确保系统运作流畅而稳健。
110 12
|
2月前
|
存储 SQL 关系型数据库
MySQL的Redo Log与Binlog机制对照分析
通过合理的配置和细致的管理,这两种日志机制相互配合,能够有效地提升MySQL数据库的可靠性和稳定性。
114 10
|
2月前
|
SQL Oracle 关系型数据库
比较MySQL和Oracle数据库系统,特别是在进行分页查询的方法上的不同
两者的性能差异将取决于数据量大小、索引优化、查询设计以及具体版本的数据库服务器。考虑硬件资源、数据库设计和具体需求对于实现优化的分页查询至关重要。开发者和数据库管理员需要根据自身使用的具体数据库系统版本和环境,选择最合适的分页机制,并进行必要的性能调优来满足应用需求。
116 11
|
2月前
|
Oracle 关系型数据库 数据库
数据库数据恢复—服务器异常断电导致Oracle数据库报错的数据恢复案例
Oracle数据库故障: 某公司一台服务器上部署Oracle数据库。服务器意外断电导致数据库报错,报错内容为“system01.dbf需要更多的恢复来保持一致性”。该Oracle数据库没有备份,仅有一些断断续续的归档日志。 Oracle数据库恢复流程: 1、检测数据库故障情况; 2、尝试挂起并修复数据库; 3、解析数据库文件; 4、导出并验证恢复的数据库文件。
|
2月前
|
存储 Oracle 关系型数据库
服务器数据恢复—光纤存储上oracle数据库数据恢复案例
一台光纤服务器存储上有16块FC硬盘,上层部署了Oracle数据库。服务器存储前面板2个硬盘指示灯显示异常,存储映射到linux操作系统上的卷挂载不上,业务中断。 通过storage manager查看存储状态,发现逻辑卷状态失败。再查看物理磁盘状态,发现其中一块盘报告“警告”,硬盘指示灯显示异常的2块盘报告“失败”。 将当前存储的完整日志状态备份下来,解析备份出来的存储日志并获得了关于逻辑卷结构的部分信息。

推荐镜像

更多