web-dev-qa-db-ja.com

複数のデータベースにわたるトランザクション-オーバーヘッドとは何ですか?

次の更新を実行します。これは、2つのデータベースにわたる単一のトランザクションです。

トランザクションはコミットしていません。

--================================================================
--RUN THE UPDATE
--================================================================

BEGIN TRANSACTION T1_radhe

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

SELECT @@TRANCOUNT

BEGIN TRY

UPDATE DEStock.DBO.ItemStock 
SET     QtyOnOrder = 0 ,
        DueDate = NULL
FROM DEStock.DBO.ItemStock T
INNER JOIN TABLEBACKUPS.DBO.__RADHE R
        ON T.ITEMNO = R.ITEMNO

print cast ( @@rowcount  as varchar) + ' updating DEStock.DBO.ItemStock '


UPDATE USStock.DBO.ItemStock 
SET     QtyOnOrder = 0 ,
        DueDate = NULL
FROM USStock.DBO.ItemStock T
INNER JOIN TABLEBACKUPS.DBO.__RADHE R
        ON T.ITEMNO = R.ITEMNO

print cast ( @@rowcount  as varchar) + ' updating USStock.DBO.ItemStock '



--COMMIT TRANSACTION T1

END TRY
BEGIN CATCH

    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    WHILE @@TRANCOUNT > 0
         ROLLBACK TRANSACTION

    SELECT 
        @ErrorMessage = ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    RAISERROR (@ErrorMessage, -- Message text.
               @ErrorSeverity, -- Severity.
               @ErrorState -- State.
               );
END CATCH

上記の更新から次の結果が得られます。

(影響を受ける196行)196 DEStock.DBO.ItemStockの更新

(影響を受ける196行)196更新USStock.DBO.ItemStock

しかし、問題のデータベースのトランザクションログを見ると、それらのログに同じビューが表示されます。

enter image description here

enter image description here

各データベースのspidは同じ6434ですが、transaction_idはデータベースごとに異なるようです。

どうですか?

また、次のスクリプトを実行した後、上記の更新でROLLBACKを実行した後も、ROLLBACKの前と同じ結果が得られました。

トランザクションが存在しないことがわかるように、オプションrecompileを追加する必要がありました。

use DEStock
go
select db_name(),@@trancount
go
Select SPID, [Master DBID], [Master XDESID], Operation, Context, [Transaction ID]
FROM sys.fn_dblog(NULL,NULL) where  [Transaction Name] = 'T1_radhe'
option (recompile)

複数のデータベースにまたがるトランザクションのオーバーヘッドはどのくらいですか?私は多くの市場を持っているので、これを頻繁に使用します。各市場には一連のデータベースがあります。

これらのトランザクションをより速く実行する方法はありますか?分散トランザクションについて考えていました。

ジョイントで使用されるテーブルはここから来ます: varchar値のリストを単一列テーブルに挿入する方法?

このリンクは、関数fn_dblogについて説明します。 SQL Server fn_dblog()関数の詳細と例

4

各データベースのspidは同じ6434ですが、transaction_idはデータベースごとに異なるようです。

どうですか?

あなたが持っているものは間違っています(あなたは同じ名前の古いトランザクションを見ているかもしれません)。

私のテストから、トランザクションIDが一致していることがわかります(以下を参照)

enter image description here

sp_WhoIsActive@get_transaction_info = 1とともに使用すると、トランザクションの詳細が下に表示されます

test_HV: 15 (1 kB),tempdb: 0 (0 kB),AdventureWorks_2005: 0 (0 kB)

簡単に データベースがクロスデータベーストランザクションの一部であるかどうかを確認 使用

-- check if database is involved in Cross database transactions
if exists (
        select *
        from fn_dblog(null, null)
        where Operation = 'LOP_PREP_XACT'
            and [Master DBID] <> 0
        )
    print 'Based on the active part of the transaction log read, there is evidence that this database has participated in cross-database transactions.'
else
    print 'Based on the active part of the transaction log read, there is no evidence of this database having participated in cross-database transactions.'

---- check for Distributed Transaction Coordinator involvement (below)
if exists (
        select *
        from fn_dblog(null, null)
        where Operation = 'LOP_PREP_XACT'
            and [Master DBID] = 0
        )
    print 'Based on the active part of the transaction log read, there is evidence that this database has participated in distributed transactions.'
else
    print 'Based on the active part of the transaction log read, there is no evidence of this database having participated in distributed transactions.'

複数のデータベースにまたがるトランザクションのオーバーヘッドは何ですか?

トランザクション自体に関連するコストはありません(または具体的には、ごくわずかです)。 私の回答からの引用

データベースをある一貫した状態から別の一貫した状態に移行するには、トランザクションが必要です。トランザクションに代わるものがないため、トランザクションにはコストがかかりません。

データベースに変更を加えると、ログレコードが生成され、tempdbスペースと共にメモリとCPUが使用されます(大きな並べ替えを実行してからレコードを更新または削除すると、tempdbへのスピルが表示されるか、スナップショット分離レベルを使用している場合、等)。

これらのトランザクションをより速く実行する方法はありますか?

はい、 バッチまたはチャンクでの更新 を実行します。最初にそれらのバッチのみを選択して更新し、関係するテーブルに適切なインデックスがあることを確認してください。これにより、SQLサーバーは行をシークして更新するだけです。

分散トランザクションについて考えていました。

データベースミラーリングまたはAlwaysONではサポートされていないため、分散トランザクションを回避します( SQL Server 2016ではサポートが制限されています )。あなたはラッキー- Orphan DTC Transaction SPID を取得します。

補足として、

  • 教育目的またはPROD以外の環境でsys.fn_dblogを使用しているのでない限り、問題はありません。 PROD環境では使用しないでください。
  • SET TRANSACTION ISOLATION LEVEL REPEATABLE READを使用しています。つまり、 幻の行(予期しない結果が生じる可能性があります) -であることを確認してくださいあなたが使用しているもの。

読み取りコミットスキャンとは異なり、繰り返し可能な読み取りスキャンは、トランザクションが終了するまで、接触するすべての行のロックを保持します。クエリ結果に該当しない行でもロックされたままになります。これらのロックにより、現在のトランザクションが完了するまで(コミットされているかロールバックされているかに関係なく)、クエリで操作された行を同時セッションで更新または削除できないことが保証されます。これらのロックは、まだスキャンされていない行を更新または削除から保護せず、すでにロックされている行の中に新しい行を挿入することを妨げません。

3
Kin Shah