2

フォーラムテーブルと多くのユーザーが同時にメッセージを挿入することを考えると、このトランザクションはどの程度安全ですか?

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

ここで、最後のMessageIdを読み取り、それをインクリメントします。グループに挿入されたメッセージごとにインクリメントする必要があるため、IDフィールドを使用できません(テーブルに挿入されたすべてのメッセージではありません)。

4

1 に答える 1

2

あなたのトランザクションは確かに非常に安全であるはずです-SERIALIZABLEトランザクションレベルのMSDNドキュメントをチェックしてください:

シリアル化可能

以下を指定します。

  • ステートメントは、変更されているが他のトランザクションによってまだコミットされていないデータを読み取ることはできません。

  • 現在のトランザクションが完了するまで、他のトランザクションは現在のトランザクションによって読み取られたデータを変更できません。

  • 他のトランザクションは、現在のトランザクションが完了するまで、現在のトランザクションのステートメントによって読み取られるキーの範囲内にあるキー値を持つ新しい行を挿入できません。

範囲ロックは、トランザクションで実行される各ステートメントの検索条件に一致するキー値の範囲に配置されます。これにより、他のトランザクションが、現在のトランザクションによって実行されるステートメントのいずれかに適格となる行を更新または挿入するのをブロックします。これは、トランザクション内のステートメントのいずれかが2回目に実行された場合、それらが同じ行のセットを読み取ることを意味します。範囲ロックは、トランザクションが完了するまで保持されます。これは、キーの全範囲をロックし、トランザクションが完了するまでロックを保持するため、分離レベルの中で最も制限があります。同時実行性が低いため、このオプションは必要な場合にのみ使用してください。このオプションは、トランザクション内のすべてのSELECTステートメントのすべてのテーブルにHOLDLOCKを設定するのと同じ効果があります。

このトランザクション分離レベルの主な問題は、サーバーにかなりの負荷がかかり、(名前が示すように)すべてのアクセスをシリアル化するため、サーバーのパフォーマンスとスケーラビリティが低下することです。たとえば、ユーザー数が非常に多い場合は、トランザクションの終了を待機しているユーザーに対して、多くのタイムアウトが発生する可能性があります。

したがって、グローバルメッセージIDのより軽量なアプローチを使用することINT IDENTITYは、間違いなくはるかに優れています。

于 2010-12-04T09:46:14.987 に答える