私の経験では、これまでに読んだプロジェクトの多くは、データベースに関係の定義がなく、ソースコードでのみ定義されていました。データベースとソースコードのテーブル間の関係を定義することの利点/欠点は何ですか?そして、より広い質問は、カスケード、トリガー、プロシージャなどの最新のデータベースの他の高度な機能についてです...私の考えにはいくつかのポイントがあります:
データベース:
設計からのデータを修正します。無効なデータを引き起こす可能性があるアプリケーションエラーを防止します。
アプリケーションがデータの整合性をチェックするためにさらにクエリを実行する必要があるため、データを挿入/更新する際のアプリケーションへのネットワークラウンドトリップを削減します。
ソースコードでは:
より柔軟。
複数のデータベースにスケーリングする場合は、リレーションがデータベース間になる場合があるため、より適切です。
データの整合性をさらに制御します。アプリケーションがデータを変更するたびにデータベースがチェックする必要はありません(複雑さはO(n)またはO(n log n)(?)の場合があります)代わりに、アプリケーションに委任されます。また、アプリケーションでデータの整合性を処理すると、データベースを使用するよりも詳細なエラーメッセージが表示されると思います。たとえば、APIサーバーを作成するときに、データベースで関係を定義すると、何かがうまくいかない場合があります(参照エンティティのように、 t存在する)の場合、メッセージとともにSQL例外が発生します。「内部サーバーエラー」が発生したことをクライアントに500で返す簡単な方法は、クライアントが何が問題なのかまったくわからないことです。メッセージを解析して何が問題なのかを判断します。これは見苦しいエラーが発生しやすい方法ですが、アプリケーションでこれを処理すると、サーバーはより意味のあるメッセージをクライアントに生成できます。
他に何かありますか?
編集:Kilianが指摘するように、パフォーマンスとデータの整合性についての私の指摘は非常に誤っています。そこで編集して、自分のポイントを修正しました。データベースにそれを処理させることは、より効率的で堅牢なアプローチになることを私は完全に理解しています。更新された質問を確認し、それについて考えてください。
編集:みんなありがとう。私が受け取ったすべての回答は、制約/関係をデータベースで定義する必要があることを指摘しています。 :)。もう1つ質問があります。この質問の範囲外であるため、別の質問として投稿しました: APIサーバーのデータベースエラーを処理する 。いくつかの洞察を残してください。
TL; DR:リレーションシップ制約はデータベースに入力する必要があります。
アプリケーションが十分に大きくありません。
実際、あなたは正しいです。データベース全体で関係を強制する場合がありますアプリケーションでそれらを強制する必要があります。
ただし、まず、使用しているデータベースソフトウェアのドキュメントを確認し、既存の製品のオファーを確認する必要があることを指摘しておきます。たとえば、PostgresとMySQLの上にクラスタリングオファーがあります。
そして、アプリケーションでsome検証が必要になったとしても、風呂の水で赤ちゃんを捨てないでください =。結局のところ、あなたがしなければならないことが少なければ少ないほど、あなたはより良く暮らしています。
最後に、将来のスケーラビリティの問題が心配な場合は、とにかくアプリケーションをスケーリングする前に、アプリケーションを大幅に変更する必要があると思います。経験則として、10倍に成長するたびに再設計する必要があります。そのため、スケーラビリティの問題の予測に失敗するのに多額の資金を投じないでください。代わりに、実際にそれらの問題が発生するポイントに到達するためにお金を使いましょう。
あなたのアプリケーションは十分に正しくありません。
あなたのアプリケーションがチェックの不完全な実装を持っている可能性と比較して、あなたが使用しているデータベースがチェックの不完全な実装を持っている可能性は何ですか?
そして、どれを最も頻繁に変更しますか?
私はデータベースが正しいことに賭けます、いつでも。
開発者は十分に分散されているとは考えていません。
アプリケーションがデータの整合性をチェックするためにより多くのクエリを実行する必要があるため、データの挿入/更新時にアプリケーションへのネットワークラウンドトリップを削減します。
赤い旗!1
あなたが考えているなら:
次に、あなたが失敗しました最も基本的な同時実行性の問題:別のプロセス/スレッドがレコードを追加している可能性があります。
あなたが考えているなら:
次に、MVCCを説明するために失敗しました:所有しているデータベースのビューは、トランザクション開始時のスナップショットです。 notは、発生しているすべての更新を表示し、コミットされていない可能性もあります。
複数のセッションにわたって制約を維持することは本当に難しい問題です。データベースで解決されてうれしいです。
1 データベースがSerializableプロパティを適切に実装していない場合。しかし実際にはほとんどありません。
最終:
アプリケーションでデータの整合性を処理すると、データベースを使用するよりも詳細なエラーメッセージが表示されると思います。例:APIサーバーを作成するとき。データベースでリレーションを定義していて、何らかの問題が発生した場合(参照されたエンティティが存在しないなど)、SQL例外とメッセージが表示されます。
エラーメッセージを解析しない、本番用データベースを使用すると、構造化エラーが返されます。少なくとも何が問題なのかを示すエラーコードがいくつかあり、このコードに基づいて適切なエラーメッセージを作成できます。
ほとんどの場合、コードで十分であることに注意してください。参照された外部キーが存在しないことを示すエラーコードがある場合、このテーブルには外部キーが1つしかない可能性が高いため、コードで問題を確認できます。 。
また、ここで正直に言いましょう。ほとんどの場合、とにかく優雅なエラーは処理しません。それらの数が非常に多く、それらすべてを説明することができないからです...
...上記のcorrectnessポイントに関連付けられています。データベースの制約が発生して処理されなかったために「500:内部サーバーエラー」が表示されるたびに、コードで処理するのを忘れたため、データベースが保存したことを意味します。
データベースは、アプリケーションがデータを変更するたびにデータの整合性をチェックする必要はありません。
これは非常に誤ったポイントです。データベースはまさにこの目的のために作成されました。データの整合性チェックが必要な場合(そして、それらが必要ないと思われる場合は、おそらく間違っているでしょう)、データベースにそれらを処理させることは、アプリケーションロジックで行うよりも確かに効率的でエラーが発生しにくくなります。
(世界最高の意志で)アプリケーションはnotであるため、制約はデータベース内にある必要がありますこのデータベースにアクセスする唯一のもの。
ある時点で、データベース内にスクリプトによる修正が必要になる場合や、展開時にテーブル間でデータを移行する必要がある場合があります。
さらに、他の要件が発生する場合があります。 「大きな顧客Xは、今日の午後、アプリケーションデータベースにインポートされたこのExcelシートのデータを本当に必要としています」。そこでは、ダーティーSQLスクリプトが間に合うようにアプリケーションコードを適合させる贅沢はありません。
これは、データベースレベルの整合性がベーコンを節約する場所です。
さらに、退職後にこの会社であなたの役割を果たし、データベースの変更を担当する開発者を想像してください。
データベース内にFK制約がない場合、テーブルを変更する前にテーブルの関係を知ることができるので、彼はあなたを嫌いますか? (手がかり、答えはイエスです)
データベースに関係があるはずです。
他の回答にあるように、制約チェックのパフォーマンスは、アプリケーション内よりデータベース内の方がはるかに優れています。データベースの制約チェックは、データベースが得意なことの1つです。
追加の柔軟性が必要な場合-例えば言及したクロスデータベース参照-次に、慎重に、そして考慮しながら制約を削除できます。データベース内に一貫性があることは、これらの制約を変更するオプションと参照整合性の確実性があることを意味します。
ドメインの問題解決コードを書くときに参照整合性を強制するコードを書いてテストする余裕は本当にありますか?
データベースレベルでデータの整合性、制約、関係などを検証しないと、本番データベースに(DBアクセスツールを含む他のクライアントを介して)アクセスできる人にとって、データを台無しにするのがはるかに簡単になります。
データベースレベルで可能な限り厳密なデータの整合性を適用することをお勧めします。私を信じてください。これは、重要なシステムで時間をかけて巨大な頭痛を救うでしょう。また、慎重に検討すると、アプリケーションロジックのエラーやビジネス要件のエラーや不整合をすばやく見つけることができます。
これへの付記として、できるだけ正規化され、アトミックな方法でデータベースを設計します。 「神」のテーブルはありません。データベースをできるだけシンプルに設計することに多くの労力を費やします。理想的には、個々に非常に明確に定義され、単一の責任ですべての列に対して慎重に検証される多数の小さなテーブルを使用します。データベースは、データ整合性の最後の保護者です。それは城の砦を表しています。
ほとんどの人は本質的に「はい、一般的にはthou shaltは常にデータベース内の関係を定義する」と言っています。しかし、コンピュータサイエンスの分野が非常に簡単な場合、「ソフトウェアエンジニア」ではなく「ソフトウェアマニュアルリーダー」と呼ばれます。制約がデータベースに含まれるべきであることに私は実際に同意しますすべきでない正当な理由がない限り、いくつかの理由を提供させてください特定の状況ではgoodと見なされる可能性があります。
重複コード
データベースで処理できる特定の機能が、アプリケーションコードに自然に存在する場合があります。 DRYの原則に違反しており、データベースと同期したアプリケーションコード。
努力
データベースが高度な機能を使用せずに必要なことをすでに実行している場合は、時間、お金、および労力をどこに配置すべきかを評価したい場合があります。制約を追加することで壊滅的な障害を防ぎ、会社に多くのお金を節約することができるなら、それはおそらく価値があります。保持する必要がある制約が追加されているが、違反されないことが既に保証されている場合は、時間を浪費し、コードベースを汚染しています。 保証は、ここで有効な言葉です。
効率
これは通常、適切な理由ではありませんが、場合によっては、特定のパフォーマンス要件があることがあります。アプリケーションコードが特定の機能をデータベースよりも高速に実装でき、さらにパフォーマンスが必要な場合は、その機能をアプリケーションコードに実装する必要がある場合があります。
コントロール
やや効率に関連しています。機能の実装方法について非常に細かい制御が必要な場合や、データベースで処理することにより、開く必要のあるブラックボックスの背後にそれを隠す場合があります。
クロージングポイント
私が最後に言うことは、データベースに機能を配置するべきではないかどうかがわかるということです。よくわからない場合は、データベース機能を使用することをお勧めします。
あなたはいくつかの非常に良い答えがありますが、いくつかのより多くのポイント
データの整合性は、データベースが設計されたものです
アプリケーションレベルでFK削除のような適切な同時実行を行うのは恐ろしいでしょう
データの整合性に関する専門知識はDBAにあります
プログラムレベルで、挿入、更新、一括更新、一括挿入、一括削除...
シンクライアント、シッククライアント、モバイルクライアント....
データの整合性はプログラマーの専門知識ではありません-多くの重複したコードと誰かがそれを台無しにするでしょう
あなたがハッキングされたとしましょう-あなたはどちらかの方法で問題を抱えていますが、データベースに整合性保護がない場合、ハッカーは小さな穴を介して多くのダメージを与えることができます
SQLまたはTSQLを介してデータを直接操作する必要がある場合があります
すべてのデータルールを誰も覚えていない
あなたの質問は意味がありません。データベースを変更できる場合はコードです。データベースを変更できない場合は、他の場所に制約を作成する必要があります。
変更できるデータベースは、Ruby、javascript、c#、adaのすべての行と同じくらい多くのコードです。
システムのどこに制約を配置するかという問題は、信頼性、コスト、開発の容易さの問題に要約されます。
いつものように、多くの答えがあります。私にとっては単純なルールを見つけました(それはモデル中心のアプローチでのみ機能します)。通常、私はアプリケーションの異なる層にのみ焦点を当てています。
モデルが複数のエンティティで構成されており、エンティティ間に依存関係がある場合、永続化レイヤーはそれらの依存関係とその可能性を反映する必要があります。したがって、RDBMSを使用している場合は、外部キーも使用する必要があります。理由は簡単です。このようにして、データは常に構造的に有効です。
この永続化レイヤーで作業を行うインスタンスはすべて、それに依存できます。インターフェース(サービス)を介してこのレイヤーをカプセル化していると思います。つまり、ここでデザインが終了し、現実の世界が始まります。
あなたのポイント、特にクロスデータベース参照を見てください。その場合、はい、RDBMS自体ではなくサービスに実装された参照があるべきではありません。しかし、この方法に従う前に、これを設計中にすでに検討した方がいいのではないでしょうか。
別のDBに保存する必要があるパーツがあることをすでに知っている場合は、そのパーツをすでにそこに配置して、別のモデルとして定義できます。正しい?
これをコードに実装することはもっと柔軟であることも指摘しています。でも、それは不完全なデザインを扱っているように聞こえませんか?どうしてもっと柔軟性が必要なのか自問してみてください。
DBでの整合性チェックによるパフォーマンスの問題は現実的ではありません。 RDBMSは、ユーザーによる実装よりもはるかに高速にそのようなことをチェックできます。どうして?まあ、メディアの混乱に対処する必要がありますが、RDBMSはそうではありません。そして、その統計a.s.oを使用することにより、そのようなチェックを最適化できます。
ご覧のとおり、すべてがデザインに戻ります。もちろん今は言うことができますが、未知の要件が現れた場合、ゲームチェンジャーはどうでしょうか。はい、それは起こるかもしれませんが、そのような変更は設計され、計画されるべきですa.s.o ..; o)
ここにはたくさんの良い答えがあります。アプリを言語Yで記述している場合は、データベース制約のようなコードをYで作成できます。その後、誰かが言語Zを使用してデータベースにアクセスしたい場合は、同じコードを再度記述する必要があります。実装が正確にでない場合、神はあなたを助けます。または、知識のあるビジネスユーザーがMicrosoft Accessを使用してデータベースに接続する場合。
私の経験によれば、人々がデータベースの制約を使いたくない場合、それは彼らが実際に何か間違った方法を試みているためです。たとえば、データの一括読み込みを試みており、しばらくの間、nullではない列をnullのままにしたいと考えています。 nullではない制約をクリティカルにした状況では「この場合はおそらく発生しない」ため、「後で修正する」予定です。別の例としては、2つの異なるタイプのデータを同じテーブルに入れようとしている場合があります。
より経験豊富な人々は一歩下がって、制約を回避しようとすることを含まない解決策を見つけます。もちろん、ビジネスは変化したため、制約はもはや適切ではなくなり、ソリューションは単に適切ではなくなった可能性があります。