簡體   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