
点击上方蓝字关注我们


前一段时间我的朋友面试被问到一个关于Oracle数据库的技术问题:执行SELECT语句是否会产生redo日志,这是考察对Oracle内部机制理解的一个实际应用问题。在Oracle数据库中,SELECT语句基本规则是不会直接产生redo日志,因为它们只是读取数据,并不对数据库中的数据做任何修改。但是,有特定情况下,即使是执行查询操作,也可能间接地导致redo日志的产生。以下是这些特殊情况的详细说明和解释。


1. 维护读一致性时的redo日志产生
当你执行一个SELECT查询时,Oracle保证你看到的数据是在查询开始时刻的一致状态,不管其他用户是否正在对这些数据进行修改。这种特性称为"读一致性"。为了实现读一致性,Oracle可能需要使用到"undo数据"。Undo数据是修改操作之前的数据副本,存储在undo表空间中。如果在你的查询执行期间,其他事务正在修改数据,你的查询会访问undo数据来重建查询开始时的数据状态。
如果Oracle首次将undo数据块加载到内存中,这个过程可能会产生redo日志。这并不是因为SELECT语句本身,而是因为Oracle需要记录undo表空间的变化,以保证在发生故障时,能够重建当时的undo状态。


2. Direct Path Reads引起的redo日志产生
在处理大型数据集时,Oracle可能决定使用一种称为"直接路径读取"的方法来高效地读取数据。这通常在全表扫描或大量数据的排序操作中发生。
如果这些操作需要额外的临时空间来处理大量数据,Oracle可能会分配新的临时段。这些分配动作是需要记录在redo日志中的,因为如果数据库发生故障,Oracle需要能够恢复这些临时段的分配状态。


3. 递归SQL导致的redo日志产生
Oracle为了维护其内部结构和优化性能,有时会自动执行一些背景操作如自动统计分析,这些操作称为"递归SQL"。这些是在用户不直接控制下,由数据库自动执行的SQL命令。
例如,当你执行一个查询时,Oracle可能会自动更新数据字典统计信息。如果这些操作涉及到对数据字典等系统对象的修改,那么这些修改就会产生redo日志。即便是一个简单的SELECT查询,也可能由于这些维护操作而间接地触发了redo日志的生成。


4. 块清理(Block Cleanout)引发的redo日志产生
当Oracle中的一个数据块在之前的DML操作(如INSERT, UPDATE, DELETE)后被标记为脏块,但是这些变更还没有被完全清理时,这个块就处于延迟清理状态。如果你的SELECT查询访问了这样的块,Oracle可能会在访问时执行清理操作,这称为“块清理”。这个过程可能会产生一些额外的redo,因为Oracle需要记录块清理的事实。
用例:
事务C更新了表中的一行数据并提交,但是块清理并未发生。当执行SELECT查询并访问这个脏块时,Oracle会进行清理,这个过程可能会产生redo记录,因为块清理的信息需要被记录下来以便进行可能的恢复。


总结
通常,SELECT语句不会直接生成redo日志,因为它们不修改数据库内容。但在维护读一致性、使用直接路径读取、执行递归SQL以及触发PL/SQL函数或数据库触发器时,可能会间接产生redo日志。了解这些情况能帮助新手数据库用户和管理员更好地理解Oracle数据库的运作机制,以及在排查问题时知道从何入手。

扫描下方二维码或添加作者微信,回复“加群”即可开启你的Oracle学习之旅。加入我们,你将获得不仅仅是知识,更有一群志同道合的朋友,一起交流,一起成长。


Oracle的SQL调化健康检查脚本介绍

中外数据库的差异究竟在什么地方

摆脱Oracle 错误码困扰,免费公益查询MOS

ORACLE运维经验之谈

解析:Oracle领航下的国产数据库航程




