河端善博 ブログ / SQL Server / PASSJ

SQL Server, .NET, PASSJ

  PASSJブログ :: ホーム :: 連絡をする :: RSS  :: ATOM :: Login
  952 投稿数 :: 112 ストーリー :: 1482 コメント :: 597 トラックバック

ニュース

Windows Live Alerts
My Yahoo!に追加
Add to Google dotnetnuke.jp
NPOPLUS.JP
MVP
PASSJ

記事のカテゴリ

過去の記事

カテゴリ

イメージギャラリ

.TEXT

INETA コミュニティ

MOM2005

MSMVP

PASSJ

SQL コミュニティ

セキュリティ TIPS

セキュリティのキホン

テスト

ブログ翻訳

多言語対応

.TEXT

INETA コミュニティ

MOM2005

MSMVP

PASSJ

SQL コミュニティ

セキュリティ TIPS

セキュリティのキホン

テスト

ブログ翻訳

多言語対応

連番管理を専用テーブルで行う方法について、考えてみました。

■方針

連番管理テーブル N を作成し、連番用レコードを事前に挿入しておく。

ID USED
A-00001 0
A-00002 0
A-00003 0

番号が必要になったら、USED = 0 の中から、最小 ID を取得し、USED = 1 に設定する

■要件

  • 番号の取得時に、ロック待ちが発生しないこと
  • 同時に取得する場合に、同じ番号を渡してしまわないこと
  • 高速であること
  • 番号を取得したトランザクションが失敗した場合、番号を返却できること

■テーブル作成クエリー

-- DROP TABLE N
 
-- テーブル N を作成
CREATE TABLE N(
    ID char(7) NOT NULL,
    USED bit NOT NULL
)
-- インデックス PK_ID を作成
CREATE INDEX PK_ID ON N (ID)
 
-- テストデータを挿入
DECLARE @NN int,
    @N char(7)
 
BEGIN TRANSACTION
SET @NN = 1
WHILE @NN < 10000
BEGIN
    SET @N = 'A-' +
        RIGHT('00000' + CONVERT(varchar, @NN), 5)
    INSERT INTO N
    VALUES (@N, 0)
    SET @NN = @NN + 1
END
-- 'A-08000' 未満を USED に設定
UPDATE N
SET USED = 1
WHERE ID < 'A-08000'
 
COMMIT TRANSACTION
 
-- 結果表示
SELECT * FROM N

■番号取得クエリー

-- トランザクション開始
BEGIN TRANSACTION
 
-- 変数宣言
DECLARE @ID char(7)
 
-- 番号を取得し、USED = 1 に設定
UPDATE N
SET USED = 1, @ID = ID
WHERE ID = (
    SELECT MIN(ID)
    FROM N WITH (READPAST)
    WHERE USED = 0
    )
 
-- 番号を表示
SELECT @ID
 
-- 任意の処理
 
-- トランザクション終了
COMMIT TRANSACTION
投稿日時 : 2004年5月19日 18:29

コメントを追加

# 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/19 19:07 Suzuki WebLog
連番管理テーブルによる、未使用の最小番号を得るクエリー

# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/20 1:17 たなか
すみません。また質問です。
上記の場合、複数のトランザクションで、サブクエリの部分だけが
パラに走って、同一の答えを返してしまう、なんていうことは無いの
でしょうか? サブクエリが答えを返して、Updateが実行される直前に
別のトランザクションでサブクエリが実行されてしまう、といった場合
です。

READPASTヒントに、UPDLOCKヒントを追加したら、良いことが起きたり
することはないのでしょうか。

# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/20 1:20 たなか
済みません。上記のようにUPDLOCKすると、今回の場合
USED=0の全てのレコードにロックが掛かってしまうのでしょうか。
だとしたら前記の対応はまずいですよね。

# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/20 5:24 河端善博
サブクエリ SELECT MIN(ID) ... の部分が同時に。
確かに、可能性がありますね。
セッション間の同期制御が必要なのかな。
確認してみたいと思います

SELECT MIN(ID) .. がとっても時間がかかるようにテスト環境をつくれば、いいのかな


# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/20 12:52 渋谷 泰宏
河端さんの投稿は SQL クエリが綺麗にカラーフォーマットされていますが、
以前に投稿されていたカラーフォーマットの SQL 版っていうのを使っていらっしゃいます?
よろしければ私にも使わせていただけないでしょうか。
私も Query Tips 的な投稿をしてみようかと思っています。

# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/20 20:44 河端善博
SQL クエリーのフォーマットには、次のものをご利用ください。
http://blogs.sqlpassj.org/yoshihirokawabata/archive/2004/03/01/826.aspx


# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/25 13:59 河端善博
次のようにするしか回避策がないようです
1. トランザクションを分ける
2. サブクエリで、TABLOCK をする
または、Win32API で、Semaphore/Mutex をつかうようにするかです。

# re: 連番管理テーブルによる、未使用の最小番号を得るクエリー 2004/05/25 13:59 河端善博
sp_getapplock も検討してみましたが、これもやはり、トランザクションの中で、ロックを解除することができませんでした

# re: XP_MSMQ 1.1 : メッセージキューの送信と受信ができる拡張ストアドプロシージャ (フリー) 2004/06/28 18:19 河端善博の .TEXT でウェブログ
re: XP_MSMQ 1.1 : メッセージキューの送信と受信ができる拡張ストアドプロシージャ (フリー)

# sp_getapplock, sp_releaseapplock による「連番管理テーブルによる、未使用の最小番号を得るクエリー 」 2007/07/18 23:02 河端善博 ブログ / SQL Server / PASSJ
sp_getapplock, sp_releaseapplock による「連番管理テーブルによる、未使用の最小番号を得るクエリー 」

コメント

タイトル:
名前:
Url:
コメント: