私は聞いた覚えジョエル・スポルスキの中で言及をポッドキャスト014(私は記憶が正しければ)彼はやっと今までに外部キーを使用したいということ。しかし、私にとっては、データベース全体で重複やそれに続くデータの整合性の問題を回避するために非常に重要なようです。
理由については、確かな理由がありますか(スタックオーバーフローの原則に沿った議論を避けるため)。
私は聞いた覚えジョエル・スポルスキの中で言及をポッドキャスト014(私は記憶が正しければ)彼はやっと今までに外部キーを使用したいということ。しかし、私にとっては、データベース全体で重複やそれに続くデータの整合性の問題を回避するために非常に重要なようです。
理由については、確かな理由がありますか(スタックオーバーフローの原則に沿った議論を避けるため)。
回答:
外部キーを使用する理由:
外部キーを使用しない理由:
ほとんどの確立されたデータベースは、強制されておらず、単なるメタデータである外部キーを指定する方法を提供していると思います(確信はありません!)。非施行はFKを使用しないすべての理由を一掃するので、2番目のセクションのいずれかの理由が当てはまる場合は、おそらくそのルートに進む必要があります。
これは育成の問題です。教育的または専門的なキャリアのどこかにデータベースの養育やケアに時間を費やした場合(またはそうした有能な人々と緊密に連携した場合)、エンティティおよび関係の基本的な信条は思考プロセスに深く根付いています。それらの初歩的なものの中には、データベースでキーを指定する方法/時期/理由(プライマリ、外部、およびおそらく代替)があります。それは第二の性質です。
ただし、過去にRDBMS関連の取り組みでこれほど徹底的または前向きな経験をしたことがない場合は、そのような情報に触れたことはないでしょう。あるいは、あなたの過去には、反データベースのような環境への没入が含まれています(たとえば、「これらのDBAは馬鹿です-私たちが選択したjava / c#コードはほとんどありません」)。この場合、あなたは激しく反対するかもしれません。あなたがただ聞くだけなら、FK(とFKが意味する可能性のある制約)は本当に重要であるとあなたに言っているいくつかのdweebの難解なせせらぎに。
ほとんどの人は子供であるときに、歯を磨くことが重要であると教えられました。あなたはそれなしでうまくいくことができますか?確かに、しかしどこかで、毎食後にブラシをかけた場合よりも歯の数が少なくなります。ママとパパがデータベース設計と口腔衛生をカバーするのに十分な責任があるとしたら、私たちはこの会話をすることはないでしょう。:-)
私はあなたがそれを回避することができる多くのアプリケーションがあると確信していますが、それは最良の考えではありません。アプリケーションを信頼してデータベースを適切に管理できるとは限りません。データベースを率直に管理することは、アプリケーションにとってあまり重要ではありません。
リレーショナルデータベースを使用している場合は、いくつかの関係を定義する必要があります。残念ながら、この態度(外部キーは必要ありません)は、データの整合性などのばかげたものに煩わされたくない(ただし、企業には専用のデータベース開発者がいないため必要になる)多くのアプリケーション開発者に採用されているようです。通常、これらのタイプでまとめられたデータベースでは、主キーだけで幸運です;)
外部キーは、リレーショナルデータベースモデルに不可欠です。
いつも使っていますが、それから金融システムのデータベースを作っています。データベースはアプリケーションの重要な部分です。財務データベースのデータが完全に正確でない場合は、コード/フロントエンド設計にどれほどの労力を費やしてもかまいません。あなたはただあなたの時間を無駄にしています。
複数のシステムが一般にデータベースと直接やり取りする必要があるという事実もあります-データを読み取るだけのその他のシステム(Crystal Reports)からデータを挿入するシステム(必ずしも私が設計したAPIを使用する必要はありません)は、 VBScriptを発見したばかりでSQLボックスのSAパスワードを持っている頭の悪いマネージャー)さてさようならデータベースは、データベースがおそらく可能なほど馬鹿に耐えられない場合です。
データが重要な場合は、はい。外部キーを使用し、一連のストアドプロシージャを作成してデータとやり取りし、最も堅牢なDBを作成します。データが重要ではない場合、データベースを作成するのはなぜですか。
更新:私は常に外部キーを使用しています。「彼らの複雑なテスト」に対する私の答えは、「データベースをまったく必要としないように単体テストを作成することです。データベースを使用するすべてのテストは、それを適切に使用する必要があり、外部キーを含みます。設定が面倒な場合は、セットアップを簡単にする方法を見つけてください。」
外部キーを使用しているとします。「金融口座を更新すると、取引の記録が保存されるはずです」という自動テストを書いています。このテストでは、あなただけの二つのテーブルに関係している:accounts
とtransactions
。
ただし、accounts
への外部キーがありcontracts
、へcontracts
のfkがありclients
、へclients
のfkがありcities
、へcities
のfkがありstates
ます。
これで、データベースは、テストに関連しない4つのテーブルにデータを設定しないと、テストを実行できなくなります。
これには少なくとも2つの考えられる見方があります。
テストの実行中に外部キーのチェックを一時的にオフにすることもできます。MySQLは、少なくともこれをサポートしています。
「レコードの削除がより面倒になる可能性があります。外部キーがその制約に違反する他のテーブルにレコードがある場合、「マスター」レコードを削除することはできません。」
SQL標準では、外部キーが削除または更新されたときに実行されるアクションが定義されていることに注意してください。私が知っているのは:
ON DELETE RESTRICT
-この列にキーを持つ他のテーブルの行が削除されないようにします。これは、ケンレイが上で説明したものです。ON DELETE CASCADE
-他のテーブルの行が削除された場合、それを参照しているこのテーブルの行を削除します。ON DELETE SET DEFAULT
-他のテーブルの行が削除された場合、その行を参照するすべての外部キーを列のデフォルトに設定します。ON DELETE SET NULL
-他のテーブルの行が削除された場合、このテーブルでそれを参照しているすべての外部キーをnullに設定します。ON DELETE NO ACTION
-この外部キーは、それが外部キーであることを示すだけです。具体的には、ORマッパーで使用します。これらと同じアクションがにも適用されON UPDATE
ます。
デフォルトはどちらに依存するようです SQL 使用しているサーバー。
@強調-これはまさにメンテナンスの悪夢を引き起こすような考え方です。
宣言的な参照整合性を無視するのはなぜでしょうか。せいぜい弱い予防策である、いわゆる「ソフトウェアの強制」を優先して、データが少なくとも一貫していることが保証されます。
それらを使用しない理由は1つあり ます。それらの役割や使用方法を理解していない場合です。
間違った状況では、外部キーの制約により、事故がウォーターフォールで複製される可能性があります。誰かが間違った記録を削除した場合、それを元に戻すことは巨大な作業になる可能性があります。
また、逆に、何かを削除する必要がある場合、設計が適切でないと、制約によってあらゆる種類のロックが発生し、それが妨げられます。
それらを使用しない正当な理由はありません ...孤立した行があなたにとって大した問題でない限り、私は推測します。
より大きな質問は:あなたは目隠しをして運転しますか?これが、参照制約のないシステムを開発する場合の方法です。ビジネス要件の変更、アプリケーション設計の変更、コードのそれぞれの論理的仮定の変更、ロジック自体のリファクタリングなどが可能であることを覚えておいてください。一般に、データベース内の制約は、現代の論理的な仮定の下に配置され、特定の論理的なアサーションおよび仮定に対して一見正しいように見えます。
アプリケーションのライフサイクルを通じて、特に新しい要件が論理アプリケーションの変更を駆動する場合、参照とデータチェックの制約により、アプリケーションを介したデータ収集が制限されます。
このリストの主題では、外部キー自体は「パフォーマンスを向上させる」ことも、リアルタイムトランザクション処理システムの観点から大幅に「パフォーマンスを低下させる」こともありません。ただし、大量の「バッチ」システムでの制約チェックには総コストがかかります。つまり、リアルタイムとバッチのトランザクションプロセスの違いです。バッチ処理-順番に処理されるバッチの、制約チェックによって発生するコストの合計がパフォーマンスに影響を与える場合。
適切に設計されたシステムでは、データの整合性チェックは、バッチを処理する「前」に行われます(ただし、ここでもコストがかかります)。したがって、ロード時に外部キー制約チェックは必要ありません。実際、外部キーを含むすべての制約は、バッチが処理されるまで一時的に無効にする必要があります。
クエリのパフォーマンス -テーブルが外部キーで結合されている場合は、外部キーの列にインデックスが付けられていないことを認識してください(ただし、それぞれの主キーには定義によりインデックスが付けられます)。さらに言えば、任意のキーにインデックスを付けて外部キーにインデックスを付け、テーブルをインデックス付きで結合することで、外部キー制約のある非インデックスキーで結合するのではなく、パフォーマンスの向上に役立ちます。
サブジェクトを変更します。データベースがWebサイトの表示/コンテンツのレンダリングなどをサポートし、クリックを記録している場合、すべてのテーブルに完全な制約があるデータベースは、そのような目的のために強制終了されます。それについて考えてください。ほとんどのウェブサイトはそのためにデータベースを使用していません。同様の要件で、データが記録されているだけで、言うまでもなく参照されている場合は、制約のないメモリ内データベースを使用します。これは、データモデルがないこと、論理モデルがないこと、物理データモデルがないことを意味しません。
私の経験では、データベースクリティカルアプリケーションでFKを使用しない方が常に良いです。FKは良い習慣だと言っている人たちには反対しませんが、データベースが巨大で、1秒あたりのCRUDオペレーションが膨大な場合は現実的ではありません。名前を付けなくても共有できます...の最大の投資銀行の1つは、データベースに単一のFKを持ちません。これらの制約は、DBに関連するアプリケーションを作成するときにプログラマーによって処理されます。基本的な理由は、新しいCRUDが実行されるときは常に、複数のテーブルに影響を与え、各挿入/更新を確認する必要があることですが、これは単一行に影響するクエリでは大きな問題にはなりませんが、処理するときに大きな遅延が発生します大手銀行が日常業務として行わなければならないバッチ処理。
FKを回避する方が適切ですが、そのリスクはプログラマーが処理する必要があります。
「レコードを追加する前に、対応するレコードが別のテーブルに存在することを確認する」がビジネスロジックです。
データベースでこれを望まないいくつかの理由を次に示します。
ビジネスルールが変更された場合は、データベースを変更する必要があります。多くの場合、データベースはインデックスを再作成する必要があり、これは大きなテーブルでは低速です。(変更ルールには、ゲストがメッセージを投稿したり、コメントを投稿したにもかかわらずユーザーが自分のアカウントを削除することを許可するなど)が含まれます。
データベースの変更は、変更を本番リポジトリにプッシュしてソフトウェア修正を展開するほど簡単ではありません。データベースの構造をできるだけ変更しないようにしたいと思います。データベース内のビジネスロジックが多いほど、データベースを変更する(および再インデックスをトリガーする)必要性が高まります。
TDD。単体テストでは、データベースをモックの代わりに使用して、機能をテストできます。データベースにビジネスロジックがある場合は、完全なテストを実行していないため、データベースでテストするか、テスト目的でコードにビジネスロジックを複製して、ロジックを複製し、ロジックが機能しない可能性を高める必要があります。同じ方法。
さまざまなデータソースでロジックを再利用する。データベースにロジックがない場合、アプリケーションはデータベースのレコードからオブジェクトを作成し、Webサービス、jsonファイル、またはその他のソースからオブジェクトを作成できます。データマッパーの実装を入れ替えるだけで、すべてのビジネスロジックを任意のソースで使用できます。データベースにロジックがある場合、これは不可能であり、データマッパーレイヤーまたはビジネスロジックにロジックを実装する必要があります。どちらの方法でも、コードにこれらのチェックが必要です。データベースにロジックがない場合は、さまざまなデータベースまたはフラットファイル実装を使用して、アプリケーションをさまざまな場所にデプロイできます。
データの一貫性を維持するのに役立つという点で、以前の回答に同意します。しかし、数週間前に、正規化された一貫性のあるデータの長所と短所について議論した興味深い投稿がJeff Atwoodにありました。
一言で言えば、非正規化されたデータベースは、大量のデータを処理するときに高速になることがあります。また、アプリケーションによっては正確な一貫性を気にする必要はありませんが、DBの場合とは異なり、データを処理するときはより注意深く行う必要があります。
Clarifyデータベースは、主キーまたは外部キーを持たない商用データベースの例です。
http://www.geekinterview.com/question_details/18869
おもしろいのは、技術ドキュメントは、テーブルがどのように関連しているか、テーブルを結合するためにどの列を使用するかなどを説明するために非常に長くなっていることです。
つまり、明示的な宣言(DRI)を使用してテーブルを結合できた可能性がありますが、結合しないことを選択しました。
その結果、Clarifyデータベースは不整合でいっぱいになり、パフォーマンスが低下します。
しかし、削除、追加の前に関連する行をチェックするなどの参照整合性を処理するコードを記述する必要がなく、開発者の作業が容易になったと思います。
そして、それが、リレーショナルデータベースに外部キー制約がないことの主な利点です。それは、少なくともそれが悪魔かもしれないケアの観点から、開発をより簡単にします。
私はOracleデータベースのみを知っており、他のデータベースは知りません。外部キーはデータの整合性を維持するために不可欠であると言えます。データを挿入する前に、データ構造を作成し、正しく作成する必要があります。これが完了すると、主キーと外部キーがすべて作成され、作業が完了します。
意味:孤立した行?いいえ、私の人生でそれを見たことはありません。悪いプログラマが外部キーを忘れたり、別のレベルで実装したりしない限り。どちらも-Oracleのコンテキストでは-データの重複、孤立データ、つまりデータの破損につながる大きなミスです。FKが適用されていないデータベースは想像できません。私には混乱のようです。これはUnixの許可システムに少し似ています。誰もがrootであると想像してください。混乱を考えてみてください。
主キーと同様に、外部キーは必須です。それは言っているようなものです:主キーを削除するとどうなりますか?まあ、完全な混乱が起こるでしょう。それがそうです。主キーまたは外部キーの責任をプログラミングレベルに移動することはできません。データレベルで行う必要があります。
欠点?そのとおり !挿入時には、さらに多くのチェックが行われるためです。ただし、データの整合性がパフォーマンスよりも重要である場合、それは非常に簡単です。Oracleでのパフォーマンスの問題は、PKおよびFKに付属しているインデックスに関連しています。
それらはレコードの削除をより厄介なものにする可能性があります-外部キーがその制約に違反する他のテーブルにレコードが存在する「マスター」レコードを削除することはできません。トリガーを使用して、カスケード削除を行うことができます。
主キーを不適切に選択した場合、その値を変更することはさらに複雑になります。たとえば、個人の名前として「customers」テーブルのPKがあり、そのキーを「orders」テーブルのFKにすると、顧客が名前を変更したい場合、それは非常に苦痛です。 。しかし、それは単なるお粗末なデータベース設計です。
私は、fireignキーを使用することの利点が、想定されるあらゆる欠点を上回ると信じています。
外部キーの制約の検証にはCPU時間を要するため、外部キーを省略してパフォーマンスを向上させる人もいます。
私もこの議論を聞いたことがあります。外部キーにインデックスを付けるのを忘れて、特定の操作が遅いと不平を言った人からです(制約チェックがインデックスを利用できるため)。まとめると、外部キーを使用しない正当な理由はありません。最新のデータベースはすべてカスケード削除をサポートしているので...
私が聞いた議論は、フロントエンドがこれらのビジネスルールを持つべきだということです。そもそも制約を破るような挿入を許可してはならない場合、外部キーは「不要なオーバーヘッドを追加」します。これに同意しますか?いいえ、しかしそれは私がいつも聞いたことです。
編集:私の推測では、彼は概念として外部キー制約ではなく、外部キー制約を参照していました。
アプリケーションのライフサイクル全体の保守性と不変性はどうですか?ほとんどのデータは、それを利用するアプリケーションよりも寿命が長いです。関係とデータの整合性は非常に重要なので、次の開発チームがアプリのコードで正しく理解できるように期待することはできません。自然な関係を尊重しないダーティデータのあるデータベースで作業していない場合は、そうします。データの整合性の重要性が非常に明確になります。
また、ほとんどのデータベースでは外部キーが必要だと思います。唯一の欠点(一貫性の強制に伴うパフォーマンスへの影響を除く)は、外部キーがあると、機能的な外部キーがあると想定してコードを記述できることです。それは決して許されるべきではない。
たとえば、参照先のテーブルに挿入し、最初の挿入が成功したことを確認せずに参照元のテーブルへの挿入を試みるコードを書く人を見てきました。後で外部キーが削除されると、データベースの一貫性が失われます。
また、更新または削除時に特定の動作を想定するオプションもありません。外部キーが存在するかどうかに関係なく、必要なことを実行するコードを作成する必要があります。カスケードされていない削除がカスケードされていると想定すると、削除は失敗します。参照されている列への更新が参照されている行に反映されていない場合、それらが反映されていると想定すると、更新は失敗します。コードを記述するために、これらの機能がない場合もあります。
これらの機能がオンになっている場合、コードはとにかくそれらをエミュレートし、パフォーマンスが少し失われます。
したがって、概要....一貫したデータベースが必要な場合は、外部キーが不可欠です。外部キーは、作成するコードに存在するか、機能していると決して想定しないでください。
私はドミトリーの答えをエコーします。
FKがもたらすパフォーマンスオーバーヘッドが心配な場合は、挿入、削除、または更新中の制約検証のコストオーバーヘッドなしに、FK制約のクエリオプティマイザーの利点を得る方法があります(Oracle)。つまり、属性RELY DISABLE NOVALIDATEを使用してFK制約を作成します。つまり、クエリオプティマイザーは、データベースが実際に制約を適用することなく、クエリの作成時に制約が適用されていると想定します。このようにFK制約をテーブルに設定する場合、責任を負うためにここで非常に注意する必要があります。これは、FK列に制約に違反するデータがないことを確実にするためです。このFK制約がオンになっているテーブルを含むクエリから、信頼できない結果が得られる可能性があります。
通常、この戦略はデータマートスキーマの一部のテーブルで使用しますが、統合ステージングスキーマでは使用しません。データのコピー元のテーブルに同じ制約が既に適用されていることを確認します。または、ETLルーチンが制約を適用します。
ここで答える人々の多くは、参照制約を介して実装される参照整合性の重要性に夢中になっています。参照整合性を備えた大規模なデータベースでの作業は、うまく機能しません。Oracleは、削除のカスケードが特に悪いようです。私の経験則では、アプリケーションはデータベースを直接更新してはならず、ストアドプロシージャを介して行う必要があります。これにより、データベース内のコードベースが維持され、データベースが整合性を維持することができます。
多くのアプリケーションがデータベースにアクセスする可能性がある場合、参照整合性の制約のために問題が発生しますが、これは制御にかかっています。
アプリケーション開発者は、データベース開発者が必ずしもそれほど精通していない可能性がある非常に異なる要件を持っている可能性があります。
基本的に1つのデータベースシステムが将来変更されないことが確実である場合は、外部キーを使用してデータの整合性を確保します。
しかし、ここに、外部キーをまったく使用しない非常に良い現実的な理由があります。
さまざまなデータベースシステムをサポートする製品を開発しています。
多くの異なるデータベースシステムに接続できるエンティティフレームワークを使用している場合は、「オープンソースの無料」サーバーレスデータベースをサポートすることもできます。これらのデータベースのすべてが外部キールール(行の更新、削除など)をサポートしているとは限りません。
これにより、さまざまな問題が発生する可能性があります。
1.)データベース構造が作成または更新されると、エラーが発生する場合があります。おそらく、外部キーはデータベースシステムによって無視されるだけなので、サイレントエラーのみになる可能性があります。
2.)外部キーに依存している場合は、ビジネスロジックでデータ整合性チェックをほとんどまたはまったく行わないでしょう。ここで、新しいデータベースシステムがこれらの外部キールールをサポートしていない場合や、別の方法で動作している場合は、ビジネスロジックを書き直す必要があります。
あなたは尋ねるかもしれません:誰が異なるデータベースシステムを必要としますか?まあ、誰もが自分のマシンで本格的なSQL Serverを購入できるわけではありません。これはソフトウェアであり、保守する必要があります。他の人たちはすでに他のDBシステムに時間とお金を投資しています。サーバーレスデータベースは、1台のマシンのみを使用する小規模なお客様に最適です。
これらのすべてのDBシステムがどのように動作するかは誰にもわかりませんが、整合性チェックを行うビジネスロジックは常に同じままです。
FKで問題が発生する可能性があるのは、(参照テーブルで)キーを参照する履歴データがあり、キーを使用可能にしたくない場合です。
明らかに解決策は、物事をよりよく前もって設計することですが、ここでは、常に完全なソリューションを制御できるわけではない現実の状況を考えています。
例:customer_type
さまざまなタイプの顧客をリストしたルックアップテーブルがある場合-特定の顧客タイプを削除する必要があるが、(ビジネス上の制約により)クライアントソフトウェアを更新できず、誰もこの状況に気付いていないソフトウェアを開発するとき、それが他のいくつかのテーブルの外部キーであるという事実は、それを参照する履歴データが無関係であることを知っていても、行を削除できない場合があります。
これで数回焦らされた後、おそらく関係のdb施行から身を乗り出すでしょう。
(私はこれが良いと言っているのではありません-FKとdbの制約を一般的に回避することを決定する理由を与えるだけです)