常にトランザクションを作成することは悪い習慣ですか?
たとえば、1つの単純なSELECT
?だけのトランザクションを作成することをお勧めします。
トランザクションが本当に必要でない場合、トランザクションを作成するコストはどれくらいですか?
READ UNCOMMITTED
のような分離レベルを使用している場合でも、それは悪い習慣ですか?
常にトランザクションを作成することは悪い習慣ですか?
ここで話しているコンテキストによって異なります。アップデートの場合は、明示的にTRANSACTIONSを使用することを強くお勧めします。 SELECTの場合はNO(明示的に)。
しかし、最初に理解すべきことがまだあるのを待ってください。SQLサーバーのすべてがトランザクションに含まれています。
セッションオプション IMPLICIT_TRANSACTIONS
がOFF
であり、明示的にbegin tran
およびcommit/rollback
を指定する場合、これは一般に Explicitトランザクション 。それ以外の場合は、自動コミットトランザクションを取得します。
IMPLICIT_TRANSACTIONS
がON
の場合、 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ログへの影響を測定するテストを行いました。
サンプルコード:
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によって強調表示されているように編集されています)
IMPLICIT&Explicit Transaction:
データベースレベルでトランザクションに関する情報を返すDMV (sys.dm_tran_database_transactions があります。
明らかに、これは影響を示すためのより単純なテストです。ディスクサブシステム、データベースの自動拡張設定、データベースの初期サイズ、同じserver\databaseで実行されている他のプロセスなどの他の要素も影響します。
上記のテストから、暗黙的トランザクションと明示的トランザクションの違いはほとんどありません。
回答にさらに追加するのを助けてくれた@TravisGanに感謝します。
SQLステートメントalwaysはトランザクションで実行されます。明示的に開始しない場合、すべてのSQLステートメントはそれ自体のトランザクションで実行されます。
唯一の選択は、1つのトランザクションに複数のステートメントをバンドルするかどうかです。複数のステートメントにまたがるトランザクションは、並行性を損なうロックを残します。したがって、「常に」トランザクションを作成することはお勧めできません。コストと利益のバランスをとる必要があります。
問題は、操作のグループを単一のアクションとして扱う必要があるかどうかです。つまり、すべての操作を正常に完了してコミットする必要があります。そうしないと、どの操作もコミットできません。予備データを読み取り、そのデータに基づいて更新を実行する必要があるシナリオがある場合、最初の読み取りはおそらくトランザクションの一部であるはずです。注:私は故意に選択/挿入/更新を避けています。トランザクションスコープは、実際にはアプリケーションレベルであり、複数のデータベース操作を伴う場合があります。飛行機の座席予約や銀行残高照会/引き出しなどの古典的なパターンを考えてみてください。アプリケーション全体が信頼性のある、一貫したデータを生成することを保証するために、問題のより広い視野をとらなければなりません。