ID列(OrderID)を持つOrdersテーブルがありますが、注文番号はOrderType(2文字)、OrderYear(2文字)、OrderID(6文字)、合計10文字(つまりXX12123456)で構成されています。このカウンターには制限があります。OrderIDとしてID999999に到達できます。次の注文のIDは7文字で構成されます。明らかに、重複した注文IDを保存することはできません。
したがって、プログレッシブOrderIDとOrderYear(たとえば、100000から999999、注文年は12から16)が事前に入力されたテーブルを作成しました。このストアドプロシージャは、SERIALIZABLE分離レベルでトランザクションを開始し、使用されていない最初の注文IDを取得し、次のように更新します。トランザクションを使用してコミットします。
Ordersテーブルであるため、注文ID計算のストアドプロシージャまたは重複した注文IDの実行でデッドロックが発生するのではないかと心配しています。
複数の同時実行スレッドを作成するコンソールアプリケーションでこれをテストし、本番環境の負荷をシミュレートするorderidを抽出しようとします。
疑問は次のとおりです。
- ID列を安全にシミュレートする別の方法がありますか?
- トリガーの使用を検討できますか?
- 異なる分離レベルを検討できますか?
- 他のアイデア?:D
ありがとう!
[編集]
たくさんのMSDNドキュメントをグーグルで読んだ後、次のように、エラーとデロックを管理し、SPから直接自動応答のタイプにアプローチする方法を示す多くの例を見つけました。
CREATEPROCEDURE[dbo]。[sp_Ordine_GetOrderID]
@AnnoOrdine AS NVARCHAR(2)= NULL OUTPUT、@ IdOrdine AS INT = NULL OUTPUT
なので
カウントをオンに設定
DECLARE @retry AS INT SET @retry = 2
トランザクション分離レベルをシリアル化可能に設定
WHILE(@retry> 0)BEGIN BEGIN TRY
BEGIN TRANSACTION OrderID
SELECT TOP 1 @AnnoOrdine = AnnoOrdine, @IdOrdine = IdOrdine
FROM ORDINI_PROGRESSIVI --WITH (ROWLOCK)
WHERE Attivo = 1
--ORDER BY AnnoOrdine ASC, IDOrdine ASC
UPDATE ORDINI_PROGRESSIVI WITH (UPDLOCK)
SET Attivo = 0
WHERE AnnoOrdine = @AnnoOrdine AND IdOrdine = @IdOrdine
IF ISNULL(@IdOrdine, '') = '' OR ISNULL(@AnnoOrdine,'') = ''
BEGIN
RAISERROR('Deadlock', 1, 1205)
END
SET @retry = 0
COMMIT TRANSACTION OrderID
SELECT @AnnoOrdine AS AnnoOrdine, @IdOrdine AS IdOrdine
END TRY
BEGIN CATCH
IF (ERROR_NUMBER() = 1205)
SET @retry = @retry - 1;
ELSE
SET @retry = -1;
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION;
END CATCH
終わり
このアプローチはデッドロックを減らします(まったくありません)が、時々私はEMPTY出力パラメーターを取得しました。30の最新スレッドでテスト済み(つまり、同時に注文を挿入する30の顧客プロセス)
ここに、ミリ秒単位のクエリ期間を含むデバッグログがあります:http://nopaste.info/285f558758.html
生産に十分な堅牢性はありますか?