web-dev-qa-db-ja.com

常にトランザクションを作成することは悪い習慣ですか?

常にトランザクションを作成することは悪い習慣ですか?

たとえば、1つの単純なSELECT?だけのトランザクションを作成することをお勧めします。

トランザクションが本当に必要でない場合、トランザクションを作成するコストはどれくらいですか?

READ UNCOMMITTEDのような分離レベルを使用している場合でも、それは悪い習慣ですか?

96
elranu

常にトランザクションを作成することは悪い習慣ですか?

ここで話しているコンテキストによって異なります。アップデートの場合は、明示的にTRANSACTIONSを使用することを強くお勧めします。 SELECTの場合はNO(明示的に)。

しかし、最初に理解すべきことがまだあるのを待ってください。SQLサーバーのすべてがトランザクションに含まれています。

セッションオプション IMPLICIT_TRANSACTIONSOFFであり、明示的にbegin tranおよびcommit/rollbackを指定する場合、これは一般に Explicitトランザクション 。それ以外の場合は、自動コミットトランザクションを取得します。

IMPLICIT_TRANSACTIONSONの場合、 Implicit transaction は、オンラインブックに記載されているステートメントタイプの1つを実行すると自動的に開始されます(例:SELECT/UPDATE/CREATE)そして明示的にコミットまたはロールバックする必要があります。このモードでBEGIN TRANを実行すると、@@TRANCOUNTがインクリメントされ、別の「ネストされた」トランザクションが開始されます)

現在のモードを切り替えるには、

SET IMPLICIT_TRANSACTIONS ON

または

SET IMPLICIT_TRANSACTIONS OFF

select @@OPTIONS & 2

上記が2を返す場合は、暗黙のトランザクションモードです。 0が返された場合は、自動コミットです。

本当に必要でない場合のトランザクション作成のコストはいくらですか

トランザクションは、データベースをある一貫した状態から別の一貫した状態にするために必要です。トランザクションに代わるものがないため、トランザクションにはコストがかかりません。参照: 行のバージョン管理ベースの分離レベルの使用

分離レベルread_uncomittedを使用している場合でも。悪い習慣ですか?ロックに問題がないはずです。

READ_UNCOMMITED分離レベルでは、定義によりダーティリードが許可されます。つまり、1つのトランザクションは、他のトランザクションによってコミットされていない変更を確認できます。この分離レベルとは、ロックのオーバーヘッドを緩和し、データベースの同時実行性を保護するためにロックを取得する方法です。

これを接続/クエリレベルで使用できるため、他のクエリに影響を与えません。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

興味深い哲学者を発見 記事 ダイニング哲学者パズルによるデッドロックについて説明し、 コミットされたスナップショットを読み取る 分離レベルについて説明するJeff Atwoodによる。

編集:

好奇心から、ログバイトフラッシュ/秒、ログフラッシュ待機/秒(ログフラッシュが発生するのを待機している1秒あたりのコミット数)などのPerfmonカウンターを使用して、以下のグラフのようにTログへの影響を測定するテストを行いました。

enter image description here

サンプルコード:

create table testTran (id int, Name varchar(8))
go

-- 19 sec
-- Autocommit transaction
declare @i int
set @i = 0
while @i < 100000
begin 
insert into testTran values (1,'Kin Shah')
set @i = @i+1
end
---------------------------------------------------
-- 2 sec
-- Implicit transaction
SET IMPLICIT_TRANSACTIONS ON
declare @i int
set @i = 0
while @i < 100000
begin 
insert into testTran values (1,'Kin Shah')
set @i = @i+1
end
COMMIT;
SET IMPLICIT_TRANSACTIONS OFF


----------------------------------------------------
-- 2 sec
-- Explicit transaction
declare @i int
set @i = 0
BEGIN TRAN
WHILE @i < 100000
Begin
INSERT INTO testTran values (1,'Kin Shah')
set @i = @i+1
End
COMMIT TRAN

トランザクションの自動コミット(@TravisGanによって強調表示されているように編集されています)

  • 挿入には19秒かかりました。
  • すべての自動コミットは、自動コミットが原因でT-logバッファーをディスクにフラッシュします(@TravisGanが強調表示された後、私が言及するのを忘れました)。
  • CHECKPOINTプロセスは高速で完了するため、頻繁に静かに実行されるため、フラッシュする必要があるダーティログバッファーの量が少なくなります。

IMPLICIT&Explicit Transaction:

  • 挿入には2秒かかりました。
  • EXPLICITトランザクションの場合、ログバッファーは、それらがいっぱいになった場合にのみフラッシュされます。
  • 自動コミットトランザクションとは異なり、EXPLICITトランザクションでは、フラッシュするログバッファーが増えるため、CHECKPOINTプロセスの所要時間が長くなります(ログバッファーがいっぱいになった場合にのみフラッシュされることに注意してください)。

データベースレベルでトランザクションに関する情報を返すDMV sys.dm_tran_database_transactions があります。

明らかに、これは影響を示すためのより単純なテストです。ディスクサブシステム、データベースの自動拡張設定、データベースの初期サイズ、同じserver\databaseで実行されている他のプロセスなどの他の要素も影響します。

上記のテストから、暗黙的トランザクションと明示的トランザクションの違いはほとんどありません。

回答にさらに追加するのを助けてくれた@TravisGanに感謝します。

109
Kin Shah

SQLステートメントalwaysはトランザクションで実行されます。明示的に開始しない場合、すべてのSQLステートメントはそれ自体のトランザクションで実行されます。

唯一の選択は、1つのトランザクションに複数のステートメントをバンドルするかどうかです。複数のステートメントにまたがるトランザクションは、並行性を損なうロックを残します。したがって、「常に」トランザクションを作成することはお勧めできません。コストと利益のバランスをとる必要があります。

36
Andomar

問題は、操作のグループを単一のアクションとして扱う必要があるかどうかです。つまり、すべての操作を正常に完了してコミットする必要があります。そうしないと、どの操作もコミットできません。予備データを読み取り、そのデータに基づいて更新を実行する必要があるシナリオがある場合、最初の読み取りはおそらくトランザクションの一部であるはずです。注:私は故意に選択/挿入/更新を避けています。トランザクションスコープは、実際にはアプリケーションレベルであり、複数のデータベース操作を伴う場合があります。飛行機の座席予約や銀行残高照会/引き出しなどの古典的なパターンを考えてみてください。アプリケーション全体が信頼性のある、一貫したデータを生成することを保証するために、問題のより広い視野をとらなければなりません。

1
Ray