繁体   English   中英

Oracle:在可序列化事务中插入后立即选择

[英]Oracle: Select immediately after insert in serializable transaction

我最近遇到了一个奇怪的问题,在Oracle数据库中编程:在一个可序列化的事务中,我做了一个大量插入(INSERT ... SELECT),然后立即打开一个带有SELECT的变量表上的游标。 我假设这个游标将包含新插入的行,但令我惊讶的是,它的内容不稳定,有时包括所有新插入的行,有时只包含一个子集。

我通过在打开光标之前提交解决了这个问题,但这种行为让我感到困惑。 可以在同一事务中插入后进行选择,而不进行干预提交,实际上是否可信? 或者这种行为是否与可序列化的事务有关?

后续 :当我尝试创建一个可重现的测试用例时,我只能在添加索引后获得此行为(在这种情况下是主键索引,在实际代码中它是常规索引)。 也许问题在于构建索引所花费的时间,因此SELECT实际上使用不完整的索引来检索结果? 无论如何,这是一个可重现的测试用例:

-- Create empty source table
CREATE TABLE TEST_CASE_1 AS 
  (SELECT 'CONTENT' AS CONTENT
   FROM DUAL
   WHERE 1 = 2)

-- Add primary key
ALTER TABLE TEST_CASE_1
ADD CONSTRAINT TEST_CASE_1_PK PRIMARY KEY (CONTENT);

-- Create empty destination table
CREATE TABLE TEST_CASE_2 AS 
  (SELECT 'CONTENT' AS CONTENT
   FROM DUAL
   WHERE 1 = 2)

-- Example of faulty code
BEGIN

  SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

  -- Populate with 100.000 rows (I used ALL_OBJECTS but any source of 100.000 rows is good)
  INSERT INTO TEST_CASE_1
    (SELECT ROWNUM 
     FROM ALL_OBJECTS
     WHERE ROWNUM <= 100000);

  INSERT INTO TEST_CASE_2
    (SELECT *
     FROM TEST_CASE_1
     WHERE CONTENT > 0);

  COMMIT;

END;

在这个例子中,我希望TEST_CASE_2也有100.000行。 再生这个测试用例(在无负载数据库中),我获得了大约400-500行插入。 删除将事务设置为可序列化的语句,我获得了正确的100.000行计数。

这似乎是一个错误; 如果您可以访问Oracle的支持网站,请查看注释1455175.1,该注释可以追溯到8i。 列出了几个错误号码(7592038 - “可选择的最新信息/可以在SERIALIZABLE中新插入的行的最新信息”,6363019)但是它们被关闭为440317的重复('隔离级别可串行化导致没有数据在所选择的行上找到AFTER INSERT'),显示为仍处于打开状态并通过开发进行调查 - 即使它最初是针对版本7(!)而提出的。

你似乎是正确的,它与PK有关。 列出的变通方法是:

  • 将执行的工作提交到那一点。
  • 执行其他(但不同的)语句(可能在回滚到事务中先前建立的保存点之后)。
  • 回滚整个事务并从头开始重新启动事务。
  • 执行全表扫描并避免使用索引。

您知道第一个解决方法已经有效,我不认为第二个或第三个会对您有所帮助吗? 您可以尝试第四次,为第二次插入的select添加/*+ FULL(TEST_CASE_1) */提示。

我没有收到11.2.0.2(Linux)中的错误,但我找不到任何暗示错误已修复的内容; 并且我没有11.1环境可以尝试 - 因此我无法检查上次解决方案是否适用于此测试用例。

有一个注意事项,您可以在11G中获得ORA-08177。 如果我在创建表后过早地运行匿名块,或者如果我插入的行太多,那么我就遇到了这个问题,这似乎与PK有关。 之前的问题可能是相关的。

似乎这将继续是一个问题,所以如果解决方法没有帮助,您可能需要重新考虑是否确实需要更改隔离级别; 如果你这样做,你可能不得不向Oracle提出服务请求以获得更好的答案。

这是一个确认的错误,Oracle表示他们不打算修复它。 以下是他们对我的服务请求的回复摘录(2015年1月):

这些症状是由于已发现已知问题的Serializable事务而您使用Bug 440317得出的结论是正确的。

错误440317 - 隔离级别可串行化导致在插入后选择的行中找不到任何数据
错误16803610 - 使用插入插入的行在可串行隔离级别转换中丢失

这两个错误都已发布,因此您可以在MOS错误搜索中查看详细信息。

根据开发情况,同一个问题有很多错误,历史很长。 设计不容易改变,因此直到分配这个功能的时刻还没有解决,这个功能并不是很有用。

开发已经关闭了错误,说代码修复是不可行的。

建议的解决方法是
应用代码修改:
在select之前更改逻辑以进行提交
或者不要使用serializable
没有应用代码修改:
不要使用表上的主键或索引

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM