我正在编写一些数据加载代码,从 Oracle 数据库中一个大而慢的表中提取数据。我对数据具有只读访问权限,并且无法更改索引或以任何方式影响查询速度。
我的 select 语句需要 5 分钟执行并返回大约 300,000 行。系统不断插入大量新记录,我需要确保获得每一条记录,因此我需要保存上次下载数据的时间戳。
我的问题是:如果我的 select 语句运行了 5 分钟,并且在 select 运行时插入了新行,我会在查询结果中收到新行吗?
我的直觉告诉我答案是“不”,特别是因为这 5 分钟中很大一部分只是将数据从数据库传输到本地环境所花费的时间,但我找不到任何直接文档关于场景。
最佳答案
"If my select statement is running for 5 minutes, and new rows get inserted while the select is running, will I receive the new rows or not in the query result?"
没有。 Oracle 强制执行严格的隔离级别,不允许脏读。
默认隔离级别是已提交读。这意味着五分钟后获得的结果集将与 Oracle 在 0.0000001 秒内交付所有记录时获得的结果集相同。查询开始运行后提交的任何内容都不会包含在结果中。这包括对记录的更新以及插入。
Oracle 通过跟踪 UNDO 表空间中表的更改来实现此目的。如果它可以限制查询将运行完成的数据中的原始图像;如果由于任何原因撤消信息被覆盖,您的查询将失败并出现可怕的 ORA-1555: Snapshot too old
。没错:Oracle 宁愿抛出异常,也不愿为我们提供不一致的结果集。
请注意,这种一致性适用于语句级别。如果我们在一个事务中运行相同的查询两次,我们可能会看到两个不同的结果集。如果这是一个问题(我认为不是您的情况),我们需要从已提交读切换到序列化隔离。
概念手册深入介绍了并发性和一致性。 Find out more.
因此,要回答您的问题,请获取开始选择时的时间戳。具体来说,在开始查询之前从表中获取 max(created_ts)
。这应该可以保护您免受 Alex 提到的差距(如果记录在插入时未提交,则如果您根据与系统时间戳进行比较进行选择,则可能会丢失记录)。尽管这样做意味着您在同一事务中发出两个查询,这意味着您毕竟需要序列化隔离!
关于oracle - 在长时间运行的查询期间插入行时会发生什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43744514/