39

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

<composite-id>複合キーを使用してレガシー データへのアクセスを許可する別の宣言があります。それ以外での使用は強くお勧めしません。

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

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

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

4

6 に答える 6

46

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

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

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

于 2013-01-01T18:11:16.813 に答える
41

あなたの質問に答えるには遅すぎるかもしれませんが、ここでは、Hibernate が代理キーを使用する必要性 (本当にアドバイスですか?) について、別の視点 (もっと穏当に願っています) を示したいと思います。

まず、代理キー (人工的に自動生成されたもの) と自然キー (ドメインの意味を持つ列で構成される) の両方に長所短所があるという事実を明確にしたいと思います。あるキー タイプが他のキー タイプよりも優れていると言うつもりはありません。要件によっては、サロゲート キーよりも自然キーの方が適している場合もあれば、その逆の場合もあります。

自然キーに関する神話

  1. 複合キーは、代理キーよりも効率が低くなります。いいえ!使用するデータベース エンジンによって異なります。
  2. 自然キーは実際には存在しません。申し訳ありませんが、それらは存在します! たとえば、航空業界では、次のタプルは、特定の予定されたフライト (航空会社、departureDate、flightNumber、operatedSuffix) に関して常に一意になります。より一般的には、ビジネス データのセットが特定の標準によって一意であることが保証されている場合、このデータのセットは [適切な] 自然キー候補です。
  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 を実行しないと、インスタンスが古いか新しいかを推測できない場合があることです。バージョンまたはタイムスタンプ プロパティはありません。

制限のいくつかの兆候(これは私が思うに、私たちはそれを呼ぶべきだと思います) はここで見つけることができます.

結論

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

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

于 2013-12-27T15:56:48.610 に答える
10

設計の観点から問題を検討します。Hibernate がそれらを良いか悪いかだけで判断するわけではありません。本当の問題は、自然キーはデータの適切な識別子として適しているかということです。

あなたのビジネス モデルでは、現在、データの一部によってレコードを識別するのが便利な場合がありますが、ビジネス モデルは時間とともに進化します。これが発生すると、データを一意に識別するために自然キーが適合しなくなっていることがわかります。また、他のテーブルの参照整合性により、変更が非常に難しくなります。

サロゲート PK を使用すると、ストレージ内でのデータの識別方法がビジネス モデル構造と連鎖しないため便利です。

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

代理キーを使用すると、アプリケーションとデータベースの設計が簡素化されます。それらは使いやすく、パフォーマンスが高く、完璧な仕事をします。

自然キーには欠点しかありません。自然キーを使用する利点は 1 つも思い浮かびません。

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

于 2013-01-01T18:29:54.040 に答える
0

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

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

したがって、ある方法が別の方法よりも優れているのではなく、キーの構築に関して、あるディレクティブが別のディレクティブに有利である可能性があります。SSAS システム インスタンスへの直接アクセスを利用するために Hibernate アプリを簡単に開発することはできません。

私は両方のキーの混合物を使用して開発を行っており、クラスター化されたインデックスを持つサロゲートが通常、私の最初の選択肢であるソリッド スターまたはスノーフレーク パターンを実装するように感じています。

したがって、OP および他の人が見ている点について: 開発 (Hibernate が専門とする) で db を不変に保ちたい場合は、代理メソッドを使用し、データの読み取りが遅くなる傾向がある場合、または特定のクエリが枯渇していることに気付いた場合パフォーマンスを向上させ、特定のデータベースに戻し、クエリの順序を最適化する複合クラスター化インデックスを追加します。

于 2014-11-26T15:49:57.717 に答える
0

主キーと一意のインデックスを混同しないでください。自然キーを使用する場合は、キーをビジネスやビジネス データにリンクします。そしてそれはあまり良くありません。そのため、データのセットを使用して複合キーを定義できたとしても、それはお勧めできません。私の見解では、複合キーは主に既存のスキーマがある場合に使用できます

于 2021-02-01T12:44:12.637 に答える