SQL Server と Oracle 間の高並列データ転送設計(初期案と改良版)

システム要件:SQL Server の一時テーブル sqlservertemp_table に格納された COMPANY, OGB04, OGA01, OGA03 フィールドを、事前にリンク済みの Oracle インスタンス ds へ転送し、Oracle 側での条件付き検索を効率化する。

初期実装手順

  1. Oracle 側にグローバル一時テーブルを作成
    CREATE GLOBAL TEMPORARY TABLE param_buffer (
        COMPANY VARCHAR2(50),
        OGB04   VARCHAR2(100),
        OGA01   VARCHAR2(100),
        OGA03   VARCHAR2(100)
    ) ON COMMIT PRESERVE ROWS;
    
  2. SQL Server 側で Oracle の一時テーブルをクリア
    EXEC ('DELETE FROM param_buffer') AT DS;
    
  3. バッチ処理による挿入(ロック回避のため)
    DECLARE @Chunk INT = 500;
    
    WHILE EXISTS (SELECT 1 FROM #TransferData)
    BEGIN
        INSERT INTO OPENQUERY(DS, 'SELECT COMPANY, OGB04, OGA01, OGA03 FROM param_buffer')
        SELECT TOP (@Chunk) COMPANY, OGB04, OGA01, OGA03
        FROM #TransferData;
    
        DELETE TOP (@Chunk) FROM #TransferData;
    
        WAITFOR DELAY '00:00:01'; -- 負荷抑制用遅延
    END
    
    DROP TABLE #TransferData;
    

初期案の課題とリスク

  • OPENQUERY と EXEC AT の性能問題
    遠隔操作は毎回ネットワークラウンドトリップを伴い、パラメータ化が不可能なため柔軟性と効率に欠ける。
  • グローバル一時テーブルの並列性欠如
    ON COMMIT PRESERVE ROWS ではセッション間でデータが干渉し、複数ユーザー同時利用時に汚染される可能性がある。
  • 全削除によるデータ競合
    DELETE FROM ... が他のセッションのデータまで消去する恐れがあり、整合性を損なう。
  • WAITFOR DELAY の非効率性
    単純な遅延はリソース待ちを解決せず、スケーラビリティを阻害する安易な対応策である。

改良版設計:セッション分離型テーブル

Oracle 側でセッション識別子を含む永続テーブルを定義:

CREATE TABLE transfer_cache (
    trace_id   VARCHAR2(64),  -- ユニークセッションID
    COMPANY    VARCHAR2(50),
    OGB04      VARCHAR2(100),
    OGA01      VARCHAR2(100),
    OGA03      VARCHAR2(100)
);

SQL Server 側で転送時に識別子を付与:

DECLARE @TraceID VARCHAR(64) = 'JOB_' + REPLACE(NEWID(), '-', '_');

WHILE EXISTS (SELECT 1 FROM #TransferData)
BEGIN
    INSERT INTO OPENQUERY(DS, 'SELECT trace_id, COMPANY, OGB04, OGA01, OGA03 FROM transfer_cache')
    SELECT TOP (@Chunk) @TraceID, COMPANY, OGB04, OGA01, OGA03
    FROM #TransferData;

    DELETE TOP (@Chunk) FROM #TransferData;
END

再利用性を高めるため、ストアドプロシージャとしてカプセル化:

CREATE PROCEDURE PushDataToOracle
AS
BEGIN
    DECLARE @TraceID VARCHAR(64) = 'JOB_' + REPLACE(NEWID(), '-', '_');
    DECLARE @Chunk INT = 500;

    EXEC ('DELETE FROM transfer_cache WHERE trace_id = ''' + @TraceID + '''') AT DS;

    WHILE EXISTS (SELECT * FROM #TransferData)
    BEGIN
        INSERT INTO OPENQUERY(DS, 'SELECT trace_id, COMPANY, OGB04, OGA01, OGA03 FROM transfer_cache')
        SELECT TOP (@Chunk) @TraceID, COMPANY, OGB04, OGA01, OGA03
        FROM #TransferData;

        DELETE TOP (@Chunk) FROM #TransferData;
    END

    SELECT @TraceID AS TransferKey;
END

タグ: SQLServer Oracle LinkedServer 高並列処理 データ転送

6月27日 01:27 投稿