DBの人工主キーを「生成」するために別のテーブルを使用したことがありますか(およびその理由)。つまり、テーブル名と現在のIDの2つの列を持つテーブルを作成します。これを使用すると、テーブル名で行をロックし、キーの現在の値を取得してインクリメントするだけで、テーブルの新しい「ID」を取得できます。 1つずつ、行のロックを解除します。標準の整数ID列よりもこれを好むのはなぜですか?
PS「アイデア」は、エンタープライズアプリケーションアーキテクチャのファウラーパターンからのものです。
DBの人工主キーを「生成」するために別のテーブルを使用したことがありますか(およびその理由)。つまり、テーブル名と現在のIDの2つの列を持つテーブルを作成します。これを使用すると、テーブル名で行をロックし、キーの現在の値を取得してインクリメントするだけで、テーブルの新しい「ID」を取得できます。 1つずつ、行のロックを解除します。標準の整数ID列よりもこれを好むのはなぜですか?
PS「アイデア」は、エンタープライズアプリケーションアーキテクチャのファウラーパターンからのものです。
これを Hi/Lo アサインメントと呼びます。
これを行うには、テーブルの INSERT でトリガーを使用して、このテーブルから ID を取得し、選択に応じて、ID を取得する前または後にそれをインクリメントします。
これは、複数のデータベース エンジンを処理する必要がある場合によく使用されます。Oracle の自動インクリメンタル識別子は、データ テーブルの BEFORE INSERT TRIGGER 内から SEQUENCE.NEXTVALUE でインクリメントする SEQUENCE によるものです。
反対に、SQL Server には IDENTITY 列があり、ネイティブに自動インクリメントされ、これは DBE 自体によって管理されます。
ソフトウェアが両方の DBE で動作するためには、何らかの標準に到達する必要があります。これに使用される最も一般的な「標準」は、主キーへの Hi/Lo 割り当てです。
これは、とりわけ 1 つのアプローチです。最近では、NHibernate などの ORM マッピング ツールを使用して、構成を通じて提供されるため、アプリケーションとデータベースの両方の側で気にする必要が少なくなります。
編集#1
この種の操作はグローバル スコープには使用できないため、データベースまたはデータベース スキーマごとにそのようなテーブルを用意する必要があります。このように、各スキーマは他のスキーマから独立しています。ただし、既存の行と競合する可能性があるため、あるスキーマのデータを同じキーを持つ別のスキーマに暗黙的に移動することはできません。
セキュリティ スキーマに関しては、別のスキーマまたはユーザーと同じデータベースにアクセスするため、特定のセキュリティ スキーマに対して追加のテーブルが存在することはありません。
SQL Server の ID または GUID 機能を使用できる場合はいつでも使用する必要があります。ただし、これが不可能な状況がいくつかあります。
1 つの例として、SQL Server ではテーブルごとに 1 つの ID 列しか許可されていません。まれに、プライベート ID とパブリック ID の両方を必要とするレコードがテーブルに含まれることがあり、ID 列が 1 つに制限されているということは、両方を整数として生成するのが面倒な場合があることを意味します。いつでも GUID を使用できますが、速度のためにプライベート ID に整数が必要であり、パブリック ID を GUID よりも人間が読みやすいものにすることもできます。
この状況では、ID を生成するための追加のテーブルが理にかなっています。しかし、私はそれを少し違う方法で行います。テーブルにはまだ 2 つの列がありますが、実際のテーブルごとに 1 つの「シャドウ」または「ID マッピング」テーブルを作成します。列の 1 つはプライベート ID (一意の制約) で、もう 1 つはパブリック ID (増分値が '7' または '13' または '1' よりも目立たないその他の数字) になります。
ここでの重要な違いは、ロックを自分で行いたくないということです。SQL Server に処理させます。
これを使用したのは、BTrieve にアプリケーションがあり、ID 列がなかったときだけです。また、彼らがこのテーブルを使用しようとしたとき、データをインポートしようとしたときに、すべての余分な読み取りと書き込みが原因で、大幅な速度低下が発生したことも言う必要があります。私の友人はそれを見て、スピードアップするために彼らが行った方法を書き直しましたが、この話の教訓は、このようなことを間違って行うと、残忍な結果が生じる可能性があるということです.
個人的には、私はこれをやりたいとは思わない。エラーの可能性が高すぎます。ID を取得する前にテーブルをロックするのを忘れたため、2 人が同じキーを使用しようとしました。これは、可能であれば RDBMS に任せるべきもののように思えます。ウィルが指摘したように、この状況を最小限に抑えるのは簡単ですが、自分が何をしているのかわからないと、そうなってしまう可能性があります。
そのテーブル名で行をロックし、キーの現在の値を取得し、それを1つインクリメントして、行のロックを解除します
簡単そうですね。
UPDATE TableOfId
SET Id += 1
OUTPUT Inserted.Id
WHERE Name = @Name;
実際には、それは惨事です。スタンドアロン操作としてアプリケーションでアクティビティが発生することはありません。すべての操作はトランザクションの一部です。「ロック解除」は実際にはコミット時にのみ発生するため、単純に行を「ロック解除」することはできません。つまり、テーブルでIDを必要とするすべてのトランザクションがシリアル化され、いつでも1つだけを続行できます。また、複数のテーブルにアクセスするトランザクションは、IDのテーブルの更新時にデッドロックが発生する可能性が高いことを意味します。これは、「次のIDの取得」更新順序を強制することが実際には難しいためです。
完全なシリアル化を回避するには、すぐにコミットできる個別のスタンドアロントランザクション(通常はUPDATE自体での暗黙的な自動コミットトランザクション)でIDを取得する必要があります。しかし、これはアプリケーションロジックを非常に複雑にします。すべての操作は、データベースへの2つの別個の接続を維持する必要があります。1つは通常のトランザクションロジックを実行するためのもので、もう1つは必要なIDを取得するためのものです。それでも、IDの更新は非常にホットスポットになる可能性があるため、目に見える競合やブロックが発生する可能性があります(Webアプリで一般的な「更新ページのヒット数+1」と同様)。
つまり、IDENTITYを使用します。IDの生成は、高い同時実行性のために最適化されています。
あなたはそれをまったく好まないでしょう。
パターンを使用したり、DB に依存したりすることで得られるものは何であれ、頭痛の種、サポート、およびパフォーマンスが失われます。
あるデータベースで作成されたデータを別のデータベースに移行、バックアップ、クラスター化、またはステージングする必要がある場合に、このパターンが使用されるのを見てきました。この状況では、まず、主キーを変更する必要がないことを確認する必要があります。次に、外部キーです。3 つ目は、外部に公開されたキーまたは永続的な参照です。