在长时间运行的查询中插入行时会发生什么

时间:2017-05-02 18:09:21

标签: oracle long-running-processes

我正在编写一些数据加载代码,用于从oracle数据库中的大型慢表中提取数据。我对数据具有只读权限,无法以任何方式更改索引或影响查询速度。

我的select语句需要5分钟才能执行,并返回大约300,000行。系统不断插入大批新记录,我需要确保每一个都记录下来,所以我需要保存上次下载数据时的时间戳。

我的问题是:如果我的select语句运行了5分钟,并且在select运行时插入了新行,我是否会在查询结果中收到新行?

我的直觉告诉我答案是“不”,特别是因为这5分钟的大部分时间都是从数据库到本地环境的数据传输所花费的时间,但我可以&# 39;找不到该方案的任何直接文件。

1 个答案:

答案 0 :(得分:8)

  

"如果我的select语句运行了5分钟,并且在select运行时插入了新行,我是否会在查询结果中收到新行?"

没有。 Oracle强制执行严格的隔离级别,并且不允许脏读。

默认隔离级别为Read Committed。这意味着,如果Oracle可以在0.0000001秒内为您提供所有记录,那么五分钟后得到的结果集将与您获得的结果集相同。查询开始运行后提交的任何内容都不会包含在结果中。这包括对记录和插入的更新。

Oracle通过跟踪UNDO表空间中表的更改来完成此操作。如果它可以限制来自该数据的原始图像,则查询将运行完成;如果由于任何原因撤消信息被覆盖,您的查询将会因可怕的ORA-1555: Snapshot too old而失败。没错:甲骨文宁愿抛出异常而不是向我们提供不一致的结果集。

请注意,此一致性适用于语句级别。如果我们在一个事务中运行两次相同的查询,我们可能会看到两个不同的结果集。如果这是一个问题(我认为不是你的情况)我们需要从Read Committed切换到Serialized隔离。

概念手册深入介绍了并发性和一致性。 Find out more.

因此,要回答您的问题,请从开始选择时开始计时。具体来说,在启动查询之前从表中取max(created_ts)。这应该可以保护您免受Alex提及的缺陷(如果在插入记录时没有提交记录,那么如果您将select与系统时间戳进行比较,则可能会丢失记录)。虽然这样做意味着您在同一个事务中发出两个查询,这意味着您确实需要序列化隔离!