SQL Serverフォーラムのクエリを挿入します
-
08-10-2019 - |
質問
フォーラムテーブルと多くのユーザーが同時にメッセージを挿入することを考慮すると、このトランザクションはどれほど安全ですか?
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
DECLARE @LastMessageId SMALLINT
SELECT @LastMessageId = MAX(MessageId)
FROM Discussions
WHERE ForumId = @ForumId AND DiscussionId = @DiscussionId
INSERT INTO Discussions
(ForumId, DiscussionId, MessageId, ParentId, MessageSubject, MessageBody)
VALUES
(@ForumId, @DiscussionId, @LastMessageId + 1, @ParentId, @MessageSubject, @MessageBody)
IF @@ERROR = 0
BEGIN
COMMIT TRANSACTION
RETURN 0
END
ROLLBACK TRANSACTION
RETURN 1
ここでは、最後のメッセージを読み、それを増やします。グループに挿入されたすべてのメッセージに対してインクリメントする必要があるため、アイデンティティフィールドは使用できません(すべてのメッセージをテーブルに挿入するわけではありません。)
解決
あなたの取引は確かにかなり安全であるべきです - チェックしてください シリアル化可能なトランザクションレベルのMSDNドキュメント:
シリアル化可能
以下を指定します。
ステートメント 変更されたデータを読み取ることができません しかし、他の取引でまだコミットされていません。
他のトランザクションはデータを変更できません 現在のトランザクションが完了するまで、現在のトランザクションによって読み取られています。
他のトランザクションは、現在のトランザクションが完了するまで、現在のトランザクションのステートメントによって読み取られるキーの範囲に分類されるキー値を持つ新しい行を挿入することはできません。
レンジロックは、トランザクションで実行された各ステートメントの検索条件に一致するキー値の範囲に配置されます。これにより、現在のトランザクションによって実行されたステートメントのいずれかの資格がある行を更新または挿入する他のトランザクションがブロックされます。これは、トランザクション内のステートメントのいずれかが2回目に実行された場合、同じ行のセットを読み取ることを意味します。レンジロックは、トランザクションが完了するまで保持されます。これは、キーの範囲全体をロックし、トランザクションが完了するまでロックを保持するため、分離レベルの中で最も制限的です。並行性は低いため、必要な場合にのみこのオプションを使用してください。このオプションは、トランザクション内のすべての選択ステートメントのすべてのテーブルにHoldLockを設定することと同じ効果があります。
このトランザクションの分離レベルの主な問題は、サーバーのかなり重い負荷であり、アクセスを意味するように(名前が示すように)アクセスすることです。トランザクションが終了するのを待っているユーザーが多くのタイムアウトを取得する可能性があります。
したがって、グローバルメッセージIDのより軽量なアプローチを次のように使用する INT IDENTITY
間違いなくはるかに優れています!