1

注意: すべての回答に感謝しますが、既にシーケンスがあります..一部のアイテムには重複が必要なため、UNIQUE制約を使用できません..PLSQLを使用してこれを処理する必要があるため、いくつかの基準に基づいて( if ステートメント) そのための重複がないことを確認する必要があります..確認するために、これらの識別子はさまざまな種類の文字列で非常にカスタマイズされています..そして、文字列の各セットについて、その文字列に対してのみカウントアップする数があります(STR-STR-####) そして、これらの STR-STR の組み合わせが何百もあり、各組み合わせに対してカウントアップする #### があります...そして、これらの STR-STR の組み合わせに加えて、いくつかの STR-STR の組み合わせが許可されます重複する..したがって、UNIQUE CONTRAINTS を使用することはできません。PRIMARY KEY は単純な数値ではないため使用できません。その上、各アイテムに PRIMARY KEY が割り当てられています。これらの識別子はユーザー用であり、データベース管理用ではありません。

ユーザーがアイテムを作成すると、いくつかの基準に基づいて、アイテムに特定の番号が付けられます。保存関数では、最初の初期文字列を準備する関数が呼び出され、次に番号が保持されているテーブルがスキャンされ、その特定の文字列に次に使用可能な 4 桁の番号が割り当てられます。

これにはいくつかの問題があります。次の番号を取得してからデータベースにコミットするまでに約 1000 行のコードがあります。問題は、2 人が数秒以内に同じ条件でアイテムを作成すると、同じ番号が発行される場合があることです。

私がやったことは、コミットの直前に、データベースで番号をチェックし、存在する場合は、関数を呼び出して、次に利用可能な番号を再度取得することです...

このコードは重複の可能性を減らしましたが、2つのアイテムを同時に保存すると、重複した番号が表示されます..

重複を回避し、重複番号の可能性を 0 にする方法を知っている人はいますか?

EDIT1: すでに主キーがあります..この識別子は特別な文字列であり、非常にカスタマイズされているため、0 からカウントアップする数値を使用することはできません。

EDIT2:重複が必要な場合もあります..これは非常にマイナーです(おそらく約10個の異なるアイテムトラックが重複を使用しています)。そのため、ifステートメントでコミットする前に重複のチェックを行う前に、 t が重複しているはずのシステムの 1 つに属している場合、チェックをスキップします...

編集 3: ここでは PL/SQL を使用しています

EDIT 4:この問題は非常に具体的で、あまり伝えていなかったと思います.多くの回答がありましたが、誰も実際に私の問題を捉えていませんでした..とにかく、私は問題を解決し、私の答えとして以下に追加しました..

4

13 に答える 13

5

コマンド CREATE SEQUENCE を検索します。オラクルは、一意の番号の生成を処理できます。(事実上) どのデータベースにもこの問題を処理する方法がありますが、実装方法は多少異なります。

[質問に編集された新しい要件への対応]

SEQUENCE を使用してカウントアップ部分を生成し、それをプレフィックスと組み合わせて、データベースに保存し直すことができます。また、重複した ID が必要なまれなケースでは、SEQUENCE から番号を取得せず、既に持っている番号を使用してください。しかし、SEQUENCE は、必要なときに保証された一意の番号を引き出すことができる「井戸」を作成するという問題を解決します。

于 2010-10-14T13:34:33.990 に答える
5

3 つのデータを 1 つのフィールドに非正規化したようです。これは、文字列フィールドに現在含まれているものです。

  • StringField char (12): STR-STR-####

これはあなたが本当に持っているべきものです(フィールド名の例のみ。これらの意味のある名前を付けるのに役立ちますが、データが何を表しているのかわかりません):

  • Str1 char (3): STR
  • Str2 char (3): STR
  • ID 整数: ####

ID フィールドでシーケンスを使用できるようになりました。

元の文字列に戻したい場合は、Str、Str2、および ID フィールドの内容を (ハイフンで区切って) 連結します。

要するに、データベースの設計が壊れており、その代償を払っているのです。私のアドバイスは、ID フィールドを 3 つの別々のフィールドに正規化して設計を修正することです。または、データベースの組み込み機能を再作成するのに何時間も費やした結果、バグが多く、競合状態に関する恐ろしい問題を抱えたソリューションになってしまうことに気付くでしょう。


または、PL/SQLでこの機能がすべて許可されている場合:

次のフィールドを含むテーブルを作成します。

  • Str1 char (3)
  • Str2 char (3)
  • 現在の ID int

それで:

  • STR-STR 識別子の可能な組み合わせごとに、"CurrentID" 値を 0 に設定して、データベースにエントリを追加します。
  • 次の ID を取得するためのストアド プロシージャを記述します。渡された STR-STR ペアに基づいて関連する行をロックし、CurrentID の値を取得し、値を増やし、行のロックを解除して、増やした値を返します。
  • 新しい ID を生成する必要があるときはいつでも、プロシージャを呼び出します。

ID を取得しようとするたびに、他の試行が完了するまで待機する必要があるため、同時実行の問題は発生しません。各 STR-STR ペアには独自のカウンターがあります。

于 2010-10-14T14:30:19.237 に答える
1

これは、関数ベースの一意のインデックスを使用して実行できます。まず、テーブルに列を追加して、識別子が各行で一意である必要があるかどうかを指定する必要があります。

alter table ... add (identifier_must_be_unique varchar2(1)
    check (identifier_must_be_unique='Y'));

次に、一意である必要がある識別子のみを保持する一意のFBIを作成します。

create unique index xxx on yyy 
(case when identifier_must_be_unique='Y' then identifier end);

最後に、識別子生成ロジックで、識別子を一意にする必要がある場合は常に、identifier_must_be_unique='Y'を設定します。それ以外の場合はnullのままにします)。その後、FBIは条件付き制約を実装します。

于 2010-10-14T14:51:17.623 に答える
1

これを提案するのはほとんど嫌いですが、あなたが決めたアプローチはかなりお粗末だったので、ここで紹介するアプローチはそれに比べてかなり良いものです. 皮肉なことを許してください。しかし、これほど多くのユーザーがあなたのアプローチは一般的に間違っていると言っている場合は、それを考慮に入れる必要があります。

おそらくどこかで、次のような SQL を実行しています。

SELECT MAX(DENORMALIZED_FIELD)
INTO   BADLY_NAMED_VARIABLE
FROM   POORLY_ORGANIZED_TABLE
WHERE  DENORMALIZED_FIELD LIKE 'ABC-XYZ%';

その後、おそらく を使用して変数を分割しSUBSTR、2 番目の部分を に解析し、NUMBERそれをインクリメントして、新しいコードで新しい変数を作成します。

できることは、ステートメントにFOR UPDATE句を追加して、問題のレコードをロックすることです。SELECT確かに、実際にそれらを更新しているわけではありませんが、定義により、操作をシリアル化する必要があります。これは、パフォーマンスが悪く、スケーラブルでなく、必要なものを取得するための汚い方法ですが、うまくいくはずです。すべての影響を確認するには、Oracle のドキュメントを確認してください。

于 2010-10-20T02:16:53.687 に答える
1

これにはいくつかの問題があります。次の番号を取得してからデータベースにコミットするまでに約 1000 行のコードがあります。問題は、2 人が数秒以内に同じ条件でアイテムを作成すると、同じ番号が発行される場合があることです。

これは心配です。これにはストアド プロシージャを実際に使用し、すべてをトランザクションにラップする必要があります。2 つのレコードの番号が異なり、問題が発生するという保証はありません。しかし、私は同意します-列を一意の識別子として設定し、主キーを使用する必要があります-それはリレーショナルデータベースだと思います!

于 2010-10-14T13:37:26.993 に答える
1

これを行うには、ある種のシリアル化プロセスが必要になる場合があります。私がお勧めする方法の 1 つは、最初の挿入時にこのフィールドを空白のままにし、プロシージャがコミットされるのを待ってから、別のプロセス (たとえば、定期的なジョブ) がこの列に入力することです。

この別のプロセスでは、ビジネス ルールに従ってすべての行が埋められます。このジョブは、この列にアクセスできる唯一のジョブであるため、同時実行の問題を回避できます。

ジョブを X 秒ごとに実行するように設定できます。これは、この設定で列が空になるわずかな遅延を意味します。または、ある種のシリアライゼーション (2 つの更新プロセスが同時に実行されないようにする行のプリエンプティブ ロック) を使用して、コミット後に最初のセッションで更新プロセスを起動させることもできます。

于 2010-10-14T14:08:59.827 に答える
1

その列に UNIQUE INDEX を使用するか、PRIMARY KEY を使用してください。

于 2010-10-14T13:32:04.397 に答える
0

壊れたデータモデルがあります。しかし、私はそれを修正することは実行可能なオプションではないと思います。最大の問題が、シーケンス値を含むテーブルに対して2つのクイック選択を実行するときにキーが重複することである場合(ここではシーケンスを使用する必要があります...ただし、それはわかっています)...次に、「select..」を使用してみてください。 .for update」は、それにアクセスするセッションの行をロックします。このロジックにより、アプリケーションに遅延が発生する可能性があることに注意してください。

于 2010-10-14T16:28:05.010 に答える
0

次のように、使用されて一意である必要があるすべての識別子を保持するテーブルを追加できます。

create table unique_identifiers (id varchar2(12) primary key);

次に、350行のロジックで、一意である必要がある「STR-STR = ####」値を生成するたびに、その値をそのテーブルに挿入します。挿入が失敗した場合は、別の番号を取得して再試行してください。

于 2010-10-14T14:45:29.040 に答える
0

Yuor コードは必ず SEQUENCE に置き換える必要があります。Oracle は、この並行性を非常にうまく管理します。

また、このシーケンスは、UNIQUE として制約された列に保存する必要があります。

于 2010-10-14T13:40:27.063 に答える
0

自動インクリメントされる PRIMARY KEY 列または UNIQUE KEY 列を作成します (AUTOINCREMENTキーワードまたは SEQUENCE を介して (Oracle のように))。そうすれば、2 人のユーザーが 2 つの正確なデータ行を同時に追加すると、データベースは 2 つの正確な値を追加しますが、それぞれに固有の ID があります。

于 2010-10-14T13:38:13.887 に答える
0

ほとんどの場合、状況全体を適切に伝えていないため、答えのどれも実際に問題を解決しませんでした..

しかし、基本的には、コミットの直前にチェックをループに入れ、更新してコミットし、同じループ内で再度チェックしました..まだ存在する場合は、ループが再び実行され、その場合、チェックが行われました..説明するのはちょっと難しいですが重複の可能性は非常に低い (ループには 100 の制限があります)

于 2010-10-14T20:05:36.673 に答える
0

明らかな何かが欠けているかもしれませんが、他の誰かが以前に提案したものに似たものを提案します。列に一意の制約を作成して、レコードを永続化しようとすると、他のプロセスがそのカスタム生成 ID を既に使用している場合に失敗します。その後、PL/SQL でその例外をトラップし、生成された一意の ID をデータベースに正常に挿入できるようになるまで、ある種の再試行ロジックを実装できます。

于 2010-10-14T16:59:01.770 に答える