深入解析:你听说过Oracle数据库的更新重启动吗?

简介: 更新重启动是 Oracle 中一个隐藏的知识点,当 Oracle 在读取数据时,会构造读一致性,当读取的内容发生了修改,Oracle 会通过 UNDO 信息来还原数据的前镜像,把数据还原到查询发生的时刻,通过构造一致性的结果来实现读取数据的一致性和隔离性。

最近看到一个比较有意思的例子,是和更新重启动有关。

更新重启动是 Oracle 中一个隐藏的知识点,当 Oracle 在读取数据时,会构造读一致性,当读取的内容发生了修改,Oracle 会通过 UNDO 信息来还原数据的前镜像,把数据还原到查询发生的时刻,通过构造一致性的结果来实现读取数据的一致性和隔离性。

Oracle 实现的读一致性也被称为多版本读一致性,每个会话都会构造自己的一致性查询版本。但是对于写操作而言,这种方式是不可能的,因为最终的数据只有一份,如要要修改数据,就只能修改唯一的这份数据,所以对读操作,访问的是一致性版本,而对于写操作,修改的永远是当前版本。

既然写操作只能修改当前版本,当写操作执行的过程中,发现要修改的记录发生了变化,破坏了更新发起时刻的一致性,这时就触发了更新重启动,也就是说更新操作会放弃之前的修改,然后重新发起一次新的更新操作。

案例一

ITPUB 上有一个有意思的案例,展示的就是更新重启动现象,链接如下:
http://www.itpub.net/forum.php?mod=viewthread&tid=2102897

这里来重现一下更新重启动,建立一张简单测试用表,在会话一插入初始数据并进行更新操作:

SQL> SET SQLP 'SQL1> '
SQL1> CREATE TABLE T_UPDATE (ID NUMBER);

Table created.
SQL1> INSERT INTO T_UPDATE SELECT ROWNUM FROM DUAL CONNECT BY LEVEL < 4;

3 rows created.
SQL1> COMMIT;

Commit complete.
SQL1> SELECT * FROM T_UPDATE;
        ID
----------
         1
         2
         3
SQL1> UPDATE T_UPDATE SET ID = 4 WHERE ID > 2;

1 row updated.

在会话 2 发起 UPDATE 语句,更新 ID 大于 0 的记录,这时 UPDATE 操作由于会话 1 更新了 ID 为 3 的记录且未提交,会处于挂起状态:

SQL> SET SQLP 'SQL2> ' 
SQL2> UPDATE T_UPDATE SET ID = ID + 0.1 WHERE ID > 0;

然后在会话 3 插入一条新的记录,并提交:

SQL> SET SQLP 'SQL3> '
SQL3> INSERT INTO T_UPDATE VALUES (0.1);

1 row created.
SQL3> COMMIT;

Commit complete.

这时回到会话1,进行提交:

SQL1> COMMIT;
Commit complete.

检查会话 2,发现更新重启动发生,UPDATE 操作更新了 4 条记录:

4 rows updated.
SQL2> SELECT * FROM T_UPDATE;
        ID
----------
       1.1
       2.1
       4.1
        .2

会话 2 中不仅更新了之前存在的三条记录,连更新语句发起之后插入并提交的第四条记录也一起进行了更新,这说明更新重启动发生在第四条记录插入之后。

论坛里问题的时序和结果如下,大家也可以参考这个范例,理解更新重启动的含义:

image

这个案例很好的展示了更新重启动现象,不过这个帖子并没有完,除了这个更新重启动的案例外,还展示了一个另外一个案例,操作和这个案例仅有很小的差别,但是结果却大不相同。
案例2
首先把数据恢复到初始状态,在会话 2 回滚之前的更新:

SQL2> ROLLBACK;     

Rollback complete.

在会话1,恢复初始的数据情况,然后开始更新数据:

SQL1> DELETE T_UPDATE WHERE ID < 1;

1 row deleted.
SQL1> UPDATE T_UPDATE SET ID = 3 WHERE ID = 4;

1 row updated.
SQL1> COMMIT;

Commit complete.
SQL1> SELECT * FROM T_UPDATE;
        ID
----------
         1
         2
         3
SQL1> UPDATE T_UPDATE SET ID = 4 WHERE ID > 2;

1 row updated.

在会话 2,对表中所有的记录的 ID 执行 UPDATE 操作,和上一个案例的唯一差别是,这里没有使用 WHERE 语句:

SQL2> UPDATE T_UPDATE SET ID = ID + 0.1;

同样在会话3插入数据并提交:

SQL3> INSERT INTO T_UPDATE VALUES (0.1);

1 row created.
SQL3> COMMIT;

Commit complete.

回到会话1,进行提交:

SQL1> COMMIT;

Commit complete.

发现会话 2 仅更新了 3 条记录:

3 rows updated.

SQL2> SELECT * FROM T_UPDATE;
        ID
----------
       1.1
       2.1
       4.1
        .1

可以清晰的看到,最后一条插入的记录并未被更新,说明更新重启动并未被触发。
对比分析
为什么带有 WHERE 条件的更新操作触发了更新重启动,而不带 WHERE 条件的更新未触发重启动呢,我是这样理解的:当 UPDATE 操作包含了 WHERE 条件,那么这个查询的结果要满足 WHERE 定义的查询一致性,当更新发现一致性不满足的情况下,就会触发更新重启动。

而对于不包含 WHERE 条件或包含 WHERE 条件但是该条件与表查询无关的情况,这时 Oracle 的目标只是将表中所有的数据进行一次更新,并不需要考虑一致性的问题。因此,这个不加 WHERE 条件的 UPDATE,感觉其实现方式上类似这种通过 ORA_ROWSCN 限定来实现:

SQL2> ROLLBACK;

Rollback complete.

回到会话 1 恢复数据,并检查 ORA_ROWSCN 的值:

SQL1> DELETE T_UPDATE WHERE ID < 1;

1 row deleted.
SQL1> UPDATE T_UPDATE SET ID = 3 WHERE ID = 4;

1 row updated.
SQL1> COMMIT;

Commit complete.
SQL1> SELECT ID, ORA_ROWSCN FROM T_UPDATE;
        ID ORA_ROWSCN
---------- ----------
         1  231512964
         2  231512964
         3  231512964
SQL1> UPDATE T_UPDATE SET ID = 4 WHERE ID > 2;

1 row updated.

在会话 2,发起包含制定 ORA_ROWSCN 限制条件的更新:

SQL2> UPDATE T_UPDATE SET ID = ID + 0.1 WHERE ORA_ROWSCN = 231512964;

会话 3 插入并提交:

SQL3> INSERT INTO T_UPDATE VALUES (0.1);

1 row created.
SQL3> COMMIT;

Commit complete.

回到会话 1,进行提交:

SQL1> COMMIT;

Commit complete.

检查会话2:

3 rows updated.
SQL2> SELECT * FROM T_UPDATE;

        ID
----------
       1.1
       2.1
       4.1
        .1

采用 ORA_ROWSCN 的效果与直接 UPDATE 不带任何 WHERE 条件是一样的,说明更新只关注 UPDATE 语句发出时刻的数据,不再考虑整体更新结果的一致性问题。

关于更新重启动的更详细的描述,建议参考ASKTOM上的回复:
https://asktom.oracle.com/pls/apex/asktom.search?tag=write-consistency

原文发布时间为:2018-07-15
本文来自云栖社区合作伙伴“数据和云”,了解相关信息可以关注“数据和云”。

相关文章
|
2月前
|
存储 Oracle 关系型数据库
服务器数据恢复—光纤存储上oracle数据库数据恢复案例
一台光纤服务器存储上有16块FC硬盘,上层部署了Oracle数据库。服务器存储前面板2个硬盘指示灯显示异常,存储映射到linux操作系统上的卷挂载不上,业务中断。 通过storage manager查看存储状态,发现逻辑卷状态失败。再查看物理磁盘状态,发现其中一块盘报告“警告”,硬盘指示灯显示异常的2块盘报告“失败”。 将当前存储的完整日志状态备份下来,解析备份出来的存储日志并获得了关于逻辑卷结构的部分信息。
|
4月前
|
存储 缓存 自然语言处理
评论功能开发全解析:从数据库设计到多语言实现-优雅草卓伊凡
评论功能开发全解析:从数据库设计到多语言实现-优雅草卓伊凡
100 8
评论功能开发全解析:从数据库设计到多语言实现-优雅草卓伊凡
|
2月前
|
存储 Oracle 关系型数据库
【赵渝强老师】Oracle RMAN的目录数据库
Oracle RMAN默认将备份元信息存储在控制文件中,但控制文件损坏或丢失会导致恢复失败,且备份增多会使控制文件无限增长。为解决这些问题,Oracle引入了RMAN目录数据库(Catalog Database),专门用于存储RMAN备份的元信息。使用目录数据库可提升备份管理效率,支持多数据库共享、长期备份历史记录存储,并可保存RMAN脚本。本文详细介绍了如何创建目录数据库、注册目标数据库及其操作步骤。
|
3月前
|
存储 关系型数据库 数据库
高性能云盘:一文解析RDS数据库存储架构升级
性能、成本、弹性,是客户实际使用数据库过程中关注的三个重要方面。RDS业界率先推出的高性能云盘(原通用云盘),是PaaS层和IaaS层的深度融合的技术最佳实践,通过使用不同的存储介质,为客户提供同时满足低成本、低延迟、高持久性的体验。
|
5月前
|
Oracle 安全 关系型数据库
【Oracle】使用Navicat Premium连接Oracle数据库两种方法
以上就是两种使用Navicat Premium连接Oracle数据库的方法介绍,希望对你有所帮助!
1080 28
|
3月前
|
存储 Oracle 关系型数据库
oracle数据恢复—oracle数据库执行错误truncate命令的数据恢复案例
oracle数据库误执行truncate命令导致数据丢失是一种常见情况。通常情况下,oracle数据库误操作删除数据只需要通过备份恢复数据即可。也会碰到一些特殊情况,例如数据库备份无法使用或者还原报错等。下面和大家分享一例oracle数据库误执行truncate命令导致数据丢失的数据库数据恢复过程。
|
5月前
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle的闪回数据库
Oracle闪回数据库功能类似于“倒带按钮”,可快速将数据库恢复至 earlier 状态,无需还原备份。本文介绍了闪回数据库的使用方法及实战案例:包括设置归档模式、开启闪回功能、记录SCN号、执行误操作后的恢复步骤等。通过具体 SQL 操作演示了如何利用闪回数据库恢复被误删的用户数据。注意,使用此功能前需确保数据库为归档模式。
158 9
|
11月前
|
存储 Oracle 关系型数据库
Oracle数据库的应用场景有哪些?
【10月更文挑战第15天】Oracle数据库的应用场景有哪些?
834 64
|
6月前
|
Oracle 关系型数据库 数据库
【赵渝强老师】Oracle数据库的闪回表
本文介绍了Oracle数据库中的闪回表(Flashback Table)功能,它能够将表的数据快速恢复到特定时间点或系统改变号(SCN),无需备份。文章通过实战示例详细演示了如何使用闪回表恢复数据,包括授权、创建测试表、记录时间与SCN号、删除数据、启用行移动功能、执行闪回操作以及验证恢复结果等步骤。同时,还展示了如何通过触发器禁止插入操作,并在闪回过程中处理触发器的启用问题。文末附有视频讲解,帮助读者更好地理解闪回表的使用方法。
226 10

推荐镜像

更多