2

一意の制約を持つ varchar(50) である行があり、新しい挿入の次の一意の番号を取得したいのですが、特定のプレフィックスが付いています。

私の行は次のようになります。

ID (varchar)
00010001
00010002
00010003
00080001

したがって、プレフィックス「0001」から次の一意の番号を取得したい場合は「00010004」になりますが、プレフィックス「0008」に必要な場合は「00080002」になります。

このテーブルには 100 万を超えるエントリがあります。Oracle 11 でこの種の操作をかなり高速に実行する方法はありますか?

このセットアップが完全に正気でないことはわかっていますが、これは私が取り組まなければならないものです。新しいテーブルなどを作成できません。

4

3 に答える 3

5

指定されたプレフィックスの最大値を検索してインクリメントできます。

SQL> WITH DATA AS (
  2     SELECT '00010001' id FROM DUAL UNION ALL
  3     SELECT '00010002' id FROM DUAL UNION ALL
  4     SELECT '00010003' id FROM DUAL UNION ALL
  5     SELECT '00080001' id FROM DUAL
  6  )
  7  SELECT :prefix || to_char(MAX(to_number(substr(id, 5)))+1, 'fm0000') nextval
  8    FROM DATA
  9   WHERE ID LIKE :prefix || '%';

NEXTVAL
---------
00010004

これが主キーを生成する非効率的な方法であることはご承知のとおりです。さらに、マルチユーザー環境ではうまく動作しないため、拡張できません。列に UNIQUE 制約があるため、同時挿入は待機してから失敗します。

プレフィックスが常に同じ長さである場合、ワークロードをいくらか減らすことができます: 最小限のステップ数で最大値を見つける特殊なインデックスを作成できます:

CREATE INDEX ix_fetch_max ON your_table (substr(id, 1, 4), 
                                         substr(id, 5) DESC);

次に、次のクエリはインデックスを使用でき、取得された最初の行で停止します。

SELECT id 
  FROM (SELECT substr(id, 1, 4) || substr(id, 5) id
          FROM your_table
         WHERE substr(id, 1, 4) = :prefix
         ORDER BY substr(id, 5) DESC)
 WHERE rownum = 1

同じ接頭辞で同時に挿入する必要がある場合はDBMS_LOCK、指定された でロックを要求するために使用することをお勧めしますnewID。誰かがすでにこの値を挿入しているために呼び出しが失敗した場合は、 を試してくださいnewID+1。これには従来のシーケンスよりも多くの作業が伴いますが、少なくとも挿入が相互に待機することはありません (デッドロックにつながる可能性があります)。

于 2013-05-29T10:13:19.593 に答える
3

これはあなたにとって非常に不満足な状況です。他のポスターが指摘しているように、シーケンスを使用しないと、ほぼ確実に並行性の問題が発生します。コメントで、あなたが大きなギャップを抱えて生きている可能性について言及しました. これは最も簡単な解決策ですが、9999 回挿入すると数字が足りなくなります。

おそらく別の方法として、プレフィックスごとに個別のシーケンスを作成することもできます。これは、プレフィックスの数がかなり少ない場合にのみ実用的ですが、実行できます。

ps - 1000000 件を超えるレコードが可能であるという要件は、実際には、データベースを再設計する以外に選択肢がないことを意味する場合があります。

于 2013-05-29T10:31:43.377 に答える