在长 运行 查询期间插入一行时会发生什么
What will happen when inserting a row during a long running query
我正在编写一些数据加载代码,从 oracle 数据库中的大型、缓慢 table 中提取数据。我对数据具有只读访问权限,无法更改索引或以任何方式影响查询速度。
我的 select 语句执行需要 5 分钟,returns 大约 300,000 行。系统不断插入大批量的新记录,我需要确保每一个都得到,所以我需要保存最后一次下载数据的时间戳。
我的问题是:如果我的 select 语句是 运行 5 分钟,并且在 select 是 运行 时插入了新行,我会收到查询结果中是否有新行?
我的直觉告诉我答案是 'no',特别是因为这 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 执行严格的隔离级别并且不允许脏读。
默认隔离级别是Read Committed。这意味着您在五分钟后获得的结果集将与您在 Oracle 可以在 0.0000001 秒内为您提供所有记录时获得的结果集相同。在查询开始 运行ning 之后提交的任何内容都不会包含在结果中。这包括对记录的更新和插入。
Oracle 通过跟踪对 UNDO table 空间中的 table 的更改来做到这一点。如果它可以限制来自该数据的原始图像,您的查询将 运行 完成;如果出于任何原因撤消信息被覆盖,您的查询将失败并出现可怕的 ORA-1555: Snapshot too old
。没错:Oracle 宁愿抛出异常也不愿为我们提供不一致的结果集。
请注意,这种一致性适用于语句级别。如果我们 运行 在一个事务中两次执行相同的查询,我们可能会看到两个不同的结果集。如果这是一个问题(我认为不是你的情况),我们需要从读取提交切换到序列化隔离。
概念手册深入介绍了并发性和一致性。 Find out more.
因此,为了回答您的问题,请从您开始 select 时获取时间戳。具体来说,在开始查询之前从 table 中获取 max(created_ts)
。这应该可以保护您免受 Alex 提到的差距(如果记录在插入时未提交,如果您将 select 与系统时间戳进行比较,则有可能丢失记录)。虽然这样做意味着您在同一个事务中发出两个查询,这意味着您毕竟需要序列化隔离!
我正在编写一些数据加载代码,从 oracle 数据库中的大型、缓慢 table 中提取数据。我对数据具有只读访问权限,无法更改索引或以任何方式影响查询速度。
我的 select 语句执行需要 5 分钟,returns 大约 300,000 行。系统不断插入大批量的新记录,我需要确保每一个都得到,所以我需要保存最后一次下载数据的时间戳。
我的问题是:如果我的 select 语句是 运行 5 分钟,并且在 select 是 运行 时插入了新行,我会收到查询结果中是否有新行?
我的直觉告诉我答案是 'no',特别是因为这 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 执行严格的隔离级别并且不允许脏读。
默认隔离级别是Read Committed。这意味着您在五分钟后获得的结果集将与您在 Oracle 可以在 0.0000001 秒内为您提供所有记录时获得的结果集相同。在查询开始 运行ning 之后提交的任何内容都不会包含在结果中。这包括对记录的更新和插入。
Oracle 通过跟踪对 UNDO table 空间中的 table 的更改来做到这一点。如果它可以限制来自该数据的原始图像,您的查询将 运行 完成;如果出于任何原因撤消信息被覆盖,您的查询将失败并出现可怕的 ORA-1555: Snapshot too old
。没错:Oracle 宁愿抛出异常也不愿为我们提供不一致的结果集。
请注意,这种一致性适用于语句级别。如果我们 运行 在一个事务中两次执行相同的查询,我们可能会看到两个不同的结果集。如果这是一个问题(我认为不是你的情况),我们需要从读取提交切换到序列化隔离。
概念手册深入介绍了并发性和一致性。 Find out more.
因此,为了回答您的问题,请从您开始 select 时获取时间戳。具体来说,在开始查询之前从 table 中获取 max(created_ts)
。这应该可以保护您免受 Alex 提到的差距(如果记录在插入时未提交,如果您将 select 与系统时间戳进行比较,则有可能丢失记录)。虽然这样做意味着您在同一个事务中发出两个查询,这意味着您毕竟需要序列化隔离!