sql >> データベース >  >> RDS >> Sqlserver

SQLServerでのトランザクションROLLBACKの使用

    はじめに

    ごく最近、私の同僚が、キーアプリケーションテーブルにWHERE句を指定せずに更新ステートメントを発行したことに必死になって私に来ました。フロントエンドへの影響は悲惨なものになるため、メールやエスカレーションが入り始める前に、どうしても状況を逆転させるための支援が緊急に必要だったため、彼は直接私に来ました。

    状況を調べたところ、変更がセカンダリデータベースに適用されていないことがわかりました。ほとんどの場合、プライマリデータベースとセカンダリデータベースの間の遅延は20分です(パフォーマンスの問題を回避するために少しずらしています)。エラーに気付いた直後に同僚が助けを求めたため、セカンダリデータベースからデータを回復することができました。このような遅延の価値については、この記事で説明しました。 。

    シナリオレビュー

    上記のシナリオは珍しいことではありません。これが通常のSQLServerユーザーに発生する理由の1つは、SQLServerがいわゆる暗黙的トランザクションを使用することです。暗黙的なトランザクションはデフォルトでオフになっています。つまり、SQL Serverは、各ステートメントの最後にCOMMITTRANSACTIONステートメントを発行することを想定していません。実際には、各ステートメントは自動的にコミットされます。これは便利であり、まだコミットされていないセッションがリソースをロックしてパフォーマンスに影響を与える状況を回避するのに役立ちます。 ブレントオザル IMPLICIT TRANSACTIONS=ONのパフォーマンスへの影響について詳しく説明します。

    ただし、この構成の小さな欠点(IMPLICIT TRANSACTIONS =OFF)は、ユーザーがステートメントを再考して、Oracleで非常に一般的なROLLBACKを発行する機会がないことです。図1は、SQL ServerManagementStudioで使用できるANSIクエリオプションを示しています。

    図。 1 SQL ServerManagementStudioのANSIデフォルト

    暗黙のトランザクションの使用

    本質的に、このデフォルト構成または最も望ましいクライアントツールで直面する問題は、SQLステートメントを実行するとロールバックできないことです。セッションで暗黙のトランザクションを有効にすることで、これを回避できます。これにより、必要に応じてトランザクションをロールバックする機会が得られます。図2と図4は、この設定を1つのセッションでのみオンにできることを示しています。ただし、これにより、ROLLBACKまたはCOMMITが発行されない場合にユーザーセッションが他のセッションをブロックするリスクを取り除くことはできません。

    >

    図。 1つのセッションでの2つの暗黙的なトランザクション

    -- Listing 1: UPDATE Table TAB2 with IMPLICIT_TRANSACTIONS ON
    SET IMPLICIT_TRANSACTIONS ON
    
    DECLARE @IMPLICIT_TRANSACTIONS VARCHAR(3) = 'OFF';  
    IF ( (2 & @@OPTIONS) = 2 ) SET @IMPLICIT_TRANSACTIONS = 'ON';  
    SELECT @IMPLICIT_TRANSACTIONS AS IMPLICIT_TRANSACTIONS;
    
    USE KTrain
    GO
    SELECT * FROM Tab2;
    GO
    
    UPDATE TAB2
    SET countryCode='SA'
    -- WHERE fname='Joyce';
    GO
    SELECT * FROM Tab2;
    GO

    図。 3すべての行が更新されました

    ここで説明する回避策を説明するために、リスト1のSQLコードを見てみましょう。ジュニア開発者である通常のSQL Serverユーザーに、特定の条件下で実行する一連のスクリプトが与えられていると仮定します。 。スクリプトでは、WHERE句がコメント化されています。これは、このスクリプトを実行するたびに、述語を変更する必要があるためです。もちろん、これは単純な使用例であり、リスクにはさまざまな方法で対処できますが、ロールバックを実行する可能性を示したいだけです。

    IMPLICIT TRANSACTIONを既にオンにしていることを思い出してください。したがって、このステートメントを実行すると、SQLServerはトランザクションをCOMMITまたはROLLBACKすることを期待します。開発者の意図は、JoyceAfamのcountryCodeを更新することです。 彼女は南アフリカに移住して以来、「SA」になりました。図3は、開発者がこれを実行しようとしているときに、値SAを countryCodeとして誤ってすべての行を更新したことを示しています。 。彼らはこれに気づき、ロールバックを発行します。

    図。 4ロールバックの発行

    図。別のセッションでの5つの暗黙のトランザクション

    ただし、IMPLICIT TRANSACTIONSをオンにしていない他のセッションでは、開発者がエラーから回復できないことがわかりました。この場合、ロールバックを正常に発行することはできません。その場合、リカバリにはデータの復元が伴います。

    図。 6暗黙のトランザクションがオンになっていないとロールバックは不可能です

    明示的なトランザクションの使用

    同じ効果を達成するための別のアプローチは、BEGIN TRANを明示的に指定することにより、DMLをトランザクションに含めることです。繰り返しになりますが、COMMITまたはROLLBACKのいずれかを使用して、トランザクションを完了することが非常に重要です。このディスカッションのコンテキストでは、コードにエラーがあることがわかったため、ROLLBACKを発行します。

    -- Listing 2: UPDATE Table TAB2 with Explicit Transaction
    
    BEGIN TRAN 
    GO
    USE KTrain
    GO
    SELECT * FROM Tab2;
    GO
    
    UPDATE TAB2
    SET countryCode='GH'
    -- WHERE fname='Joyce';
    GO
    SELECT * FROM Tab2;
    GO
    
    ROLLBACK;
    
    SELECT * FROM Tab2;
    GO
    
    - Listing 3: Corrected UPDATE Statement
    
    BEGIN TRAN 
    GO
    USE KTrain
    GO
    SELECT * FROM Tab2;
    GO
    
    UPDATE TAB2
    SET countryCode='SA'
    WHERE fname='Joyce';
    GO
    SELECT * FROM Tab2;
    GO

    結論

    この記事では、ロールバックの機会を作成し、誤ったDMLに起因するユーザーエラーを軽減するための適切な回避策について簡単に触れました。また、このアプローチの主なリスクである、不注意によるブロッキングについても説明しました。 DBAは、 sys.dm_tran_session_transactions、sys.dm_tran_locks にクエリを実行することにより、このリスクが存在する可能性について調査を開始できます。 、および同様の動的管理オブジェクト。

    参照

    1. ログ配布と遅延リカバリを使用したデータ損失の修正

    2. 暗黙のトランザクションを設定

    3. 暗黙のトランザクションを悪い考えに設定する

    4. トランザクションのDMV


    1. プログラムによるSQLコードの生成

    2. Ubuntu16.10でPostgreSQLを9.6から10.0にアップグレードします

    3. SQLでbool値を設定する方法

    4. 都市の列ごとに従業員の名前を配置する必要があります