programing

하나의 활성 세션에서만 ORA-08177을 무작위로 얻습니다.

magicmemo 2023. 6. 10. 08:42
반응형

하나의 활성 세션에서만 ORA-08177을 무작위로 얻습니다.

테이블을 만든 다음 데이터를 삽입하는 프로그램을 실행하고 있습니다.
데이터베이스에 액세스하는 유일한 프로그램입니다.
ORA-08177을 무작위로 받고 있습니다.
실제 코드는 다소 복잡하지만, 저는 이 동작을 재현하는 간단한 프로그램을 작성했습니다.

using System;
using System.Data;
using Oracle.DataAccess.Client;

namespace orabug
{
  class Program
  {
    private const string ConnectionString = ""; // Valid connection string here

    // Recreates the table
    private static void Recreate()
    {
      using (var connection = new OracleConnection(ConnectionString)) {
        connection.Open();
        using (var command = connection.CreateCommand()) {
          command.CommandText = @"
            declare
              table_count binary_integer;
            begin
              select count(*) into table_count from sys.user_tables where table_name = 'TESTTABLE';
              if table_count > 0 then
                execute immediate 'drop table TestTable purge';
              end if;
              execute immediate 'create table TestTable(id nvarchar2(32) primary key)';
            end;";
          command.ExecuteNonQuery();
        }
        connection.Close();
      }
    }

    // Opens session sessionCount times, inserts insertCount rows in each session.
    private static void Insert(int sessionCount, int insertCount)
    {
      for (int sessionNumber = 0; sessionNumber < sessionCount; sessionNumber++)
        using (var connection = new OracleConnection(ConnectionString)) {
          connection.Open();
          using (var transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
            for (int insertNumber = 0; insertNumber < insertCount; insertNumber++)
              using (var command = connection.CreateCommand()) {
                command.BindByName = true;
                command.CommandText = "insert into TestTable (id) values(:id)";
                var id = Guid.NewGuid().ToString("N");
                var parameter = new OracleParameter("id", OracleDbType.NVarchar2) {Value = id};
                command.Parameters.Add(parameter);
                command.Transaction = transaction;
                command.ExecuteNonQuery();
              }
            transaction.Commit();
          }
          connection.Close();
        }
    }

    static void Main(string[] args)
    {
      int iteration = 0;
      while (true) {
        Console.WriteLine("Running iteration: {0}", iteration);
        try {
          Recreate();
          Insert(10, 100);
          Console.WriteLine("No error");
        }
        catch (Exception exception) {
          Console.WriteLine(exception.Message);
        }
        iteration++;
      }
    }
  }
}

이 코드는 무한 주기로 실행됩니다.
각 반복마다 다음 작업을 10회 수행합니다.

  • 세션 열기

  • 랜덤 데이터가 있는 100개의 행 삽입

  • 세션 닫기

  • 오류가 발생하지 않았다는 메시지를 표시합니다.

오류가 발생하면 예외가 발견되고 해당 메시지가 인쇄된 다음 다음 반복이 실행됩니다.

다음은 샘플 출력입니다.보시다시피 ORA-08177은 인터리빙을 성공적으로 수행하고 있습니다.

Running iteration: 1
No error
Running iteration: 2
ORA-08177: can't serialize access for this transaction
Running iteration: 3
ORA-08177: can't serialize access for this transaction
Running iteration: 4
ORA-08177: can't serialize access for this transaction
Running iteration: 5
ORA-08177: can't serialize access for this transaction
Running iteration: 6
ORA-08177: can't serialize access for this transaction
Running iteration: 7
No error
Running iteration: 8
No error
Running iteration: 9
ORA-08177: can't serialize access for this transaction
Running iteration: 10
ORA-08177: can't serialize access for this transaction
Running iteration: 11
ORA-08177: can't serialize access for this transaction
Running iteration: 12
ORA-08177: can't serialize access for this transaction
Running iteration: 13
ORA-08177: can't serialize access for this transaction
Running iteration: 14
ORA-08177: can't serialize access for this transaction
Running iteration: 15
ORA-08177: can't serialize access for this transaction
Running iteration: 16
ORA-08177: can't serialize access for this transaction
Running iteration: 17
No error
Running iteration: 18
No error
Running iteration: 19
ORA-08177: can't serialize access for this transaction
Running iteration: 20
No error

Oracle 11.1.0.6.0을 실행하고 있으며 ODP.NET 2.111.6.20을 사용하고 있습니다.
격리 수준 변경ReadCommited문제를 해결하지만, 저는 정말로 이것을 실행하고 싶습니다.Serializable수평의
이 문제는 저 혼자가 아닌 것 같은데 답변이 없어서 다시 문의드립니다.
제가 무엇을 잘못하고 있으며 어떻게 이 문제를 해결할 수 있을까요?

APC에 의해 편집

다른 사람이 잘못된 트리를 발견하는 것을 방지하기 위해 게시된 코드 샘플은 ORA-8177 오류의 생성기일 뿐입니다.분명히 실제 코드는 다릅니다. 구체적으로 테이블을 떨어뜨리고 다시 만드는 것은 빨간 청어입니다.

전체 다시 쓰기(처음에 잘못된 트리를 제거함).

직렬화 가능 분리 수준은 관심 있는 트랜잭션 목록의 슬롯을 차지합니다.Oracle이 슬롯을 얻지 못하면 ORA-8177을 던집니다.사용 가능한 ITL 슬롯의 수는 INITRANS 및 MAXTRANS에 의해 제어됩니다.설명서에 따르면:

직렬화 가능 모드를 사용하려면 INITRANS를 3 이상으로 설정해야 합니다.

테이블과 해당 인덱스 모두에 대해 설정해야 합니다.그렇다면, 당신의 INITRANS 설정은 무엇입니까?샘플 코드는 기본값(테이블의 경우 1, 인덱스의 경우 2)을 사용합니다.

사용자 Gary는 댓글에 이 이상한 행동을 설명하는 스레드 링크를 게시했습니다.인덱스 재구성 중에 실행 취소 데이터를 사용할 수 없게 되는 경우가 있습니다.직렬화 가능한 격리 수준에서 실행되고 이 인덱스와 어떤 식으로든 관련된 데이터를 요청하는 모든 트랜잭션은 ORA-08177을 얻게 됩니다.이것은 Oracle의 반 버그 기능입니다.행 종속성은 이 오류가 발생할 가능성을 줄입니다.애플리케이션의 경우 대용량 데이터 업로드를 위해 ReadCommitted 수준으로 전환했습니다.이 문제를 완전히 벗어날 수 있는 다른 방법은 없는 것 같습니다.

감사합니다, 게리. 다른 질문에 대한 당신의 답변을 지지합니다.

언급URL : https://stackoverflow.com/questions/2326750/randomly-getting-ora-08177-with-only-one-active-session

반응형