0

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

生産に十分な堅牢性はありますか?

4

1 に答える 1

0

現在の解決策が問題を引き起こしていることに気づき、それが起こらない可能性がある場合は、ID列とダミーフィールドを使用して、作成するIDタイプごとにテーブルを作成することもできます。

すなわち:

 ABtypeID (ABID int identity(1,1), dummy varchar(1))

次に、このテーブルにレコードを挿入し、組み込み関数を使用してIDを取得できます。

すなわち

insert ABTypeID (dummy) values (null)
select Scope_Identity()

これらのテーブルから必要に応じて削除し、年末に切り捨ててIDカウンターをリセットできます。

ロールバックされるトランザクションで挿入をラップすることもできます-ID値はロールバックの影響を受けません

于 2012-10-19T08:08:08.177 に答える