web-dev-qa-db-ja.com

休止状態で複合キーが推奨されないのはなぜですか?

これは Hibernate公式チュートリアル からです:

代替案があります<composite-id>複合キーでレガシーデータへのアクセスを許可する宣言。それ以外の用途には使用しないことを強くお勧めします。

複合キーが推奨されないのはなぜですか?私は、すべての列が外部キーであり、モデルで意味のある関係である主キーを形成する3列のテーブルの使用を検討しています。これが悪い考えである理由はわかりません。特に、インデックスを使用することになります。

代替は何ですか?自動生成された追加の列を作成し、それを主キーとして使用しますか?とにかく3つの列を照会する必要があります!?

要するに、なぜこの声明は真実なのでしょうか?そして、より良い代替手段は何ですか?

37
Isaac

彼らはいくつかの理由でそれらを思いとどまらせます:

  • それらは使用するのが面倒です。たとえばWebアプリケーションでオブジェクト(または行)を参照する必要があるたびに、1つではなく3つのパラメーターを渡す必要があります。
  • 彼らは非効率的です。単に整数をハッシュする代わりに、データベースは3つの列の複合をハッシュする必要があります。
  • これらはバグにつながります。開発者は、主キークラスのequalsおよびhashCodeメソッドを必然的に実装します。または、変更可能にして、HashSetまたはHashMapに格納された値を変更します
  • それらはスキーマを汚染します。別のテーブルがこの3列のテーブルを参照する必要がある場合、外部キーとして1つの列ではなく3つの列が必要です。次に、同じ設計に従って、この3列の外部キーをこの新しいテーブルの主キーの一部にすると、4列の主キーがすぐに作成され、次のテーブルに5列のPKが作成されます。等々、データの重複や汚いスキーマにつながります。

代わりに、他の3つの列に加えて、自動生成された単一列の主キーを使用することもできます。 3つの列のタプルを一意にする場合は、一意制約を使用します。

44
JB Nizet

質問に答えるのが遅すぎる場合でも、ここでは、Hibernateが代理キーを使用する必要性(本当にアドバイスですか?)について別の観点(もっと適度に期待します)を示したいと思います。

まず最初に両方という事実を明確にしたい代理キー(人工的に自動生成されたもの)と自然キー(ドメインの意味を持つ列で構成される)には、proscons。あるキータイプが他のキータイプよりも優れているとは言いません。私はあなたの要件によっては、自然な鍵が代理の鍵よりも良い選択であるかもしれないと言っています。

自然な鍵に関する神話

  1. 複合キーは、代理キーよりも効率的ではありません。番号!使用するデータベースエンジンによって異なります。
  2. 自然キーは実際には存在しません。申し訳ありませんが、存在します!たとえば、航空業界では、次のタプルは特定のscheduledフライト(航空会社、departureDate、flightNumber、operationalSuffix)に関して常に一意です。より一般的には、ビジネスデータのセットが特定の標準によって一意であることが保証されている場合、このデータのセットは[良い]自然キーの候補です。
  3. 自然キーは子テーブルの「スキーマを汚染」します。私にとって、これは実際の問題というよりも感じです。それぞれが2バイトの4列の主キーを持つことは、11バイトの単一列よりも効率的かもしれません。さらに、4つの列を使用して、親テーブルに結合せずに(where句で4列を使用して)子テーブルを直接クエリできます。

代理キーの短所

代理キーは次のとおりです。

  1. パフォーマンスの問題の原因:
    • これらは通常、自動インクリメントされた列を使用して実装されます。つまり、
      • 新しいIDを取得するたびにデータベースへのラウンドトリップ(これは、キャッシュまたは[seq] hiloのようなアルゴリズムを使用して改善できることは承知していますが、これらのメソッドには独自の欠点があります)。
      • ある日、あるスキーマから別のスキーマにデータを移動する必要がある場合(少なくとも私の会社ではかなり定期的に発生します)、IDの衝突の問題が発生する可能性があります。そしてはい、私はあなたがUUIDを使用できることを知っていますが、それらは最後の32桁の16進数が必要です! (データベースのサイズを気にする場合は、問題になる可能性があります)。
      • すべての代理キーに1つのシーケンスを使用している場合、確かに-データベースで競合が発生します。
  2. エラーを起こしやすい。シーケンスにはmax_valueの制限があるため、開発者は次の事実に注意する必要があります。
    • シーケンスを循環させる必要があります(最大値に達すると、1,2、...に戻ります)。
    • データの順序付け(時間の経過)としてシーケンスを使用している場合は、循環のケースを処理する必要があります(Id 1の列は、Id max-value-1の行よりも新しい場合があります)。
    • コード(および、内部IDであると想定されるために発生してはならないクライアントインターフェイス)が、シーケンス値の格納に使用した32b/64b整数をサポートしていることを確認してください。
  3. 重複しないデータを保証するものではありません。列の値はすべて同じであるが生成された値が異なる2つの行を常に使用できます。私にとって、これは[〜#〜] [〜#〜]データベース設計の観点から見た代理キーの問題です。
  4. ウィキペディアの詳細...

Hibernateが代理キーを好む/必要とする理由

Java Persistence with Hibernateリファレンスに記載されているように:

より経験豊富なHibernateユーザーは、saveOrUpdate()のみを使用します。特に混合状態のオブジェクトのより複雑なネットワークでは、Hibernateに新しいものと古いものを判断させる方がはるかに簡単です。排他的なsaveOrUpdate()の唯一の(それほど深刻ではない)欠点は、データベースでSELECTを実行せずにインスタンスが古いか新しいかを推測できない場合があることです。たとえば、クラスが自然な複合キーでマップされている場合、バージョンまたはタイムスタンププロパティはありません。

limitationのいくつかの症状(これは、私たちはそれを呼び出す必要があると思います)を見つけることができます here

結論

あなたの意見をあまりにも二乗しないでください。適切な場合は自然キーを使用し、適切な場合は代理キーを使用します。

これが誰かを助けたことを願っています!

39
mwnsiri

設計の観点から問題を考えます。 Hibernateがそれらを良いか悪いかと考えるだけではありません。本当の質問は次のとおりです:自然なキーは私のデータの良い識別子になるための良い候補ですか?

今日のビジネスモデルでは、一部のデータでレコードを識別するのが便利ですが、ビジネスモデルは時間とともに進化します。そして、これが発生すると、自然キーがデータを一意に識別するために適合しなくなることがわかります。そして、他のテーブルの参照整合性により、これは物事を[〜#〜] much [〜#〜]変更しにくくします。

ストレージでのデータの識別方法ビジネスモデル構造を連鎖させないため、代理PKがあると便利です。

シーケンスから自然キーを生成することはできません。データで識別できないデータの場合は、 much より頻繁です。これは、自然キーがストレージキーとは異なることを示す証拠であり、一般的な(そして適切な)アプローチと見なすことはできません。

代理キーを使用すると、アプリケーションとデータベースの設計が簡単になります。それらは使いやすく、より高性能で、完璧な仕事をします。

自然キーは欠点のみをもたらします。自然キーを使用することの単一の利点を考えることはできません。

そうは言っても、Hibernateには自然な(構成された)キーに関する実際の問題はないと思います。しかし、休止状態のコミュニティは代理キーの利点を広く認めているため、おそらくいくつかの問題(またはバグ)や、ドキュメントの問題やヘルプの取得を見つけることになるでしょう。したがって、複合キーを選択した理由について、適切な回答を用意してください。

10

Hibernateのドキュメントが正しく理解されている場合:

「複合キーを使用してレガシーデータへのアクセスを許可する別の<composite-id>宣言があります。それ以外の場合は使用しないでください。」

トピック5.1.4についてidタグxml <id>を使用すると、主キーマッピングが早すぎるため、休止状態のドキュメントでは、複合主キーマッピングに<composite-id> xmlタグではなく<id>を使用しないようにできます。 [〜#〜] not [〜#〜]複合主キーを使用するには、参照を負にします。

1

ツールとしてデータベースを使用して開発されたアプリケーションは、クエリの最適化にクラスター化されたインデックスを使用して、代理キーのワークフローを維持するのに間違いなく有益です。

データウェアハウジングとOLAPスタイルのシステムですが、大規模なファクトテーブルを使用してディメンションの代理キーを結び付けるために特別な注意が必要です。この場合、データによって、ダッシュボード/アプリケーションがレコードを維持するために使用できます。

したがって、1つのメソッドが別のメソッドよりも好ましいのではなく、おそらく1つのディレクティブが別のメソッドよりも有利であることが重要です。SSASシステムインスタンスへの直接アクセスを利用するHibernateアプリを簡単に開発することはできません。

私は両方の主要な混合物を使用して開発し、クラスター化されたインデックスを持つサロゲートが通常、最初の選択肢です。

そのため、OPやその他の見方について:(Hibernateが専門とする)開発でdbを不変のままにしたい場合-サロゲートメソッドを使用し、データの読み取りが遅くなる傾向がある場合、または特定のクエリのドレインに気付いた場合パフォーマンス、特定のデータベースに戻し、クエリの順序を最適化する複合クラスター化インデックスを追加します。

0
Nathan Teague