コードではなくデータベースに制約が適用されるのはなぜですか?


21

データベースに制約が適用されるのはなぜですか?それをコードに入れることはより柔軟ではないでしょうか?

データベースの実装に関する初心者向けの本を読んでいるので、これを初心者として尋ねています。このエンティティモデルを含むデータベースを設計したとしましょう。

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

現在の制約:

  1. システムの登録者は、学生または従業員のみです。
  2. 個人エンティティには社会的番号の一意性が必要です。これは、すべての個人が一意の一意の名前(別名、十分に優れた主キー)のみを保持していることを前提としています。(#1を参照)

後で番号1を削除することにしました。ある日、大学がTeacherEmployeeサブタイプ)もStudent自由時間でコースを取ると決定した場合、数千、数百万、数十億のデータベース設計を変更するのははるかに困難です。コードのロジックを変更するだけでなく、数十億のエントリ:学生と従業員の両方として個人を登録することを許可しなかった部分のみ。

ありそうもないことですが、今のところ他に何も考えられません。 どうやらそれは可能です)。

コードではなくデータベース設計でビジネスルールを重視するのはなぜですか?

#1:7年後のメモ、実際の例:
私は、ミスのために発行されたSSNが複製された政府を見ました:複数の人々、同じSSN。元のDBの設計者は、この一意性制約をデータベースに適用しないという間違いを間違いなく犯しました。(そして元のアプリケーションのバグ?共有データベースを使用している複数のアプリケーションが制約をどこに置き、チェックし、強制することに同意しませんか?...)。
このバグは、今後何年もの間、システムその後に開発されたすべてのシステムで存続し、元のシステムのデータベースに依存します。ここで答えを読んで、可能な限り多くの制約をデータベースに賢明に(盲目的にではなく)適用して、現実の物理的な世界をできるだけうまく表現することを学びました。


2
ほとんどの場合、ビジネスルールが適用されていることと、そのための最善の方法が重要です。
ypercubeᵀᴹ

3
エンティティの柔軟性とデータベースの拡張性は主に正規化によって定義されるため、実際に使用されている制約の非常に悪い例を示しています。とはいえ、制約は、アプリケーションにバグが発生した場合でも、新しいアプリケーションが開発された場合でも、外部APIが追加された場合でも、誰かが直接DBを編集した場合でも、破損データがデータベースに侵入することに対する最終的な保護手段です。制約はデータベースを保護しますが、それに加えて、ビジネスロジックもDBにアクセスする前に独自の処理を行う必要があります。
ニールスケレンテス

3
実際、大学院生として、私は学生、従業員、教師の両方と考えられています。あなたの例は本当にありそうもない。
ウィンストンイーバート

4
アプリケーションのオブジェクトに基づいてデータベース設計を行うことは絶対にしないでください。これを人として通常設計し、次に人の役割を定義する関連テーブルを作成します。その後、問題は発生しません;人々が複数の役割を持つことができる役割のために、あなたが表を持っているので、起きません。ロール担当者を1人だけにしたい場合は、peopleIDが一意になるようにテーブルを制約します。変更したい場合は、制約を削除します。
HLGEM

オブジェクト<->リレーショナルマッピングは芸術です。
トールビョーンラヴンアンデルセン

回答:


34

いくつかの制約はデータベースで最適に実施され、いくつかはアプリケーションで最適に実施されます。

製品に有効なを確保するための外部キー制約など、データモデルの構造の基本であるため、データベースに最もよく適用される制約が通常ありますcategory_id

すべてのFooBar製品は青色である必要があるなど、アプリケーションに適用される制約はデータモデルの基本ではない場合がありますが、後でFooBarsを黄色にすることもできます。これはアプリケーションロジックであり、データベースに実際に存在する必要はありませんが、別のcoloursテーブルを作成でき、データベースは製品がそのテーブルから有効なエントリを参照することを要求できます。しかしのみで記録することを決定はcolours価値があるblueだろう、まだどこから来るの外のデータベースを。

データベースに制約がなく、アプリケーションにすべての制約を適用する必要がある場合はどうなるかを検討してください。データを操作する必要のあるアプリケーションが複数ある場合はどうなりますか?異なるアプリケーションが異なる制約を強制することを決定した場合、データはどのようになりますか?

あなたの例は、データベースではなくアプリケーションに制約を設定するほうが有益かもしれない状況を示していますが、おそらく初期データモデルが制限的で柔軟性に欠けるという根本的な問題がありましたか?


したがって、この回答によれば、ルールは<個人は学生のサブタイプテーブルにのみ存在するか、従業員サブタイプテーブルにのみ存在する>をコードに適用する必要があり、データベースには<学生/従業員サブタイプが有効でなければなりませんperson>制約。私は正しいですか?(それは本の例でした)。ありがとう。
-hkoosha

2
@loolooyyyy:はい、それは正しいと思います。データベースが最初のルール(人は学生または従業員にしかなれない)を実施する場合、あなたが説明した状況(従業員がクラスに登録したい)は不可能です。おそらく第三者(政府など)から発行された社会保障番号を共有できないため、2番目の「個人」レコードを作成することもできます。もちろん、この過度に制限的なデータモデルは、場合によっては機能する可能性があります
...-FrustratedWithFormsDesigner

2
@loolooyyyy:元のデータモデルを使用し、教師を生徒にするための別の方法は、Socialの代わりにを参照する新しい外部キーと、システムで生成されたプライマリキーを持つteachers_as_students別のサブタイプをStudents呼び出すことですTeachers。セキュリティ番号。このように、「学生」は実際には教師のエイリアスであるため、教師はクラスを受講するために登録できます。データモデル全体を見ずにこれがどれだけうまく機能するかを確実に言うのは困難です。
FrustratedWithFormsDesigner

2
これを断った。制約が適用されるのは、アプリケーションのみに限定されるのが最も良いときですこの回答のトーンは不適切に重み付けされています。
エヴァンキャロル

3
@FrustratedWithFormsDesignerは確かに、実際には外部キー制約の子です。dbアクセスポイントの異なるバージョン/ビルドの3つのクライアントがあり、赤でその製品の出荷を停止したらどうしますか?可能な色の組み合わせのリストをどこに保存しますか?ヒント:私はあなたのための中央集権的な場所を持っています。あなたがテーブルを作成する場合とcolor_products、そしてcolorほとんどのIDE /スキーマローダー、FKEYS以下のサポート- 、あなたはおそらく、より簡単に追加のドロップダウンを作成することができます。
エヴァンキャロル

35

なぜなら:

  1. 私がしたいすべてのデータベース内のデータは同じ制約を受けることだけでなく、新しいデータは、今日実行しているコードのバージョンで制約を受けることができます。
  2. プログラムによる制約ではなく、宣言的な制約が必要です。
  3. 多くの場合、データベース内のデータは、今日データベースとやり取りするために記述されたコードよりも長持ちします。そして、コードではなくそのデータが組織の資産です。
  4. すべてのデータが厳密な制約を受けることを知っていると、コードがはるかに単純になります。データベースが不可能であることを保証することを知っている特別なケースを考慮する必要はもうありません。

私にとって重要な理由がいくつかあります。


4
(1)と(3)に準関連:アプリケーションコードのバグは修正できますが、データのバグは修復できないことがよくあります。
muが短すぎる

17

データは、おそらくアプリケーションコードより長く存続します。ルールが時間の経過とともに役立つデータにとって重要な場合(データの整合性を保つのに役立つ外部キー制約など)、それはデータベース内になければなりません。そうしないと、データベースにヒットする新しいアプリケーションで制約が失われる危険があります。複数のアプリケーションがデータベースにヒットするだけでなく(重要なデータルールがあることに気付かない可能性があるものを含む)、データインポートやレポートアプリケーションなど、それらの一部はメインデータ入力アプリケーションで設定されたデータレイヤーを使用できない場合があります。率直に言って、制約にバグがある可能性は、私の経験ではアプリケーションコードではるかに高いです。

私個人の意見では(多くの異なる目的で使用される数百の異なるデータベースでの30年以上のデータ処理と経験に基づいて)、所属するデータベースに制約を設定しない人は最終的に貧弱なデータを持ちます。時々、使用できないほどの不良データ。これは、特定の監査基準を満たす必要がある財務/規制データがある場合に特に当てはまります。


17

データベースの外部に実装されている参照整合性制約のほとんどは無効にできるため、データの整合性を常に保証したい場合は、データベースに制約を適用する必要があります。完全停止、それだけです。

通常、アプリケーションレベルの制約は、データベースが一貫性メカニズムを読み取っても無効になります。これにより、セッションは、コミットされるまで他のセッションのデータを表示できません。

たとえば、2つのセッションが、一意であることが意図されている列に同じ値を挿入しようとする場合があります。値がまだ存在しないことを同時に確認し、値を挿入し、コミットすることができます。データベースに実装された一意の制約では、これは起こりません。

ちなみに、これはアプリケーション言語の設計者には不明です。読むのセクション3.10一意Railsのガイドのルビー:Active Recordのバリデーションとコールバック

このヘルパーは、オブジェクトが保存される直前に属性の値が一意であることを検証します。データベースに一意性制約は作成されません。そのため、2つの異なるデータベース接続が、一意にする列に同じ値を持つ2つのレコードを作成することがあります。これを回避するには、データベースに一意のインデックスを作成する必要があります。


16

データベースによって実施される制約の利点:

シンプルさ -制約の宣言は、制約を宣言し、その宣言を強制するコードを記述するよりもはるかに簡単です。

正確性 -作成しなかったコードには、作成したバグが含まれることはありません。データベースベンダーは、制約コードが正確であることを確認するために時間を費やしているため、その必要はありません。

速度 -アプリケーションは、ベースとなるデータベースよりも多くのディストリビューションを持つことはできません。データベースベンダーは、制約コードが効率的であることを確認するために時間を費やしているため、その必要はありません。データベース自体も、アプリケーションがどれほど効率的であっても、データへのアクセスが高速です。

再利用-1つのプラットフォームで1つのアプリケーションから始めることはできますが、そのままではない場合があります。異なるOS、異なるハードウェア、または音声インターフェイスからデータにアクセスする必要がある場合はどうなりますか?データベースに制約を設定することにより、このコードを新しいプラットフォーム用に書き直したり、デバッグのために正確にしたり、速度をプロファイルしたりする必要がなくなります。

完全性 -アプリケーションは、データがデータベースに入力されるときに制約を適用し、古いデータが正確であることを確認したり、データベースにすでにあるデータを操作したりするために追加の作業が必要になります。

長寿命 -データベースプラットフォームは、特定のアプリケーションよりも長持ちする可能性があります。


11

サーバーに制約が適用されるのはなぜですか?悪者にクライアントを使用させることはできません。

明確にするために、クライアントアプリケーションでビジネスルール処理のみを行う場合、別のツールを使用しているユーザーがデータベースサーバーに接続し、ビジネスルールや整合性チェックに制約されることなく、必要な処理を実行できます。ネットワーク上の任意の場所で誰かが任意のツールを使用できないようにすることは非常に困難です。

データベースサーバーで整合性チェックを行うと、ツールに関係なく、データにアクセスしようとするたびに、ルールによって制約されます。


10

ここにいくつかの素晴らしい答えがあり、他の考えを繰り返すリスクがあります:

  • SSNは必ずしも一意ではありません。ちなみに、SSNは常に知られているわけではなく、場合によっては(まだ)存在しません。SSNは再利用でき、すべての従業員または学生がSSNを持っているとは限りません。これは質問の周辺ですが、制約をどこで実施するかに関係なく、ビジネスルールに関する決定を下すにはデータモデルとドメインを十分に理解する必要があることを示しています。
  • 個人的には、制約を可能な限りデータに近づけることを好みます。非常に単純な理由は、誰もがアプリケーションコードを使用してデータベース内のデータを変更するわけではないということです。アプリケーションレベルでビジネスルールを実施UPDATEし、データベースに対して直接ステートメントを実行する場合、アプリケーションはどのようにして無効な変更を防止しますか?アプリのビジネスルールに関する別の問題は、特に全員が同時に更新を取得できない可能性がある分散アプリの場合、再コンパイル/再展開が困難になる可能性があることです。最後に、アプリケーションのビジネスルールを変更しても、新しいルールに違反する既存のデータについてはまったく何もしません。データに新しい制約を追加する場合は、データを修正する必要があります。
  • さまざまなレベルで複数の冗長なチェックを正当化できる場合があります。これはすべて、展開方法の柔軟性、変更の可能性、およびデータベースと他のレイヤーでビジネスルールの変更を同期することがどれだけ難しいかによって異なります。アプリ層でチェックを繰り返すことの説得力のある議論は、データベースへのラウンドトリップを潜在的に防止することができるということです(制約の性質と既存のデータに依存するかどうかによってます)。ただし、どちらかを選択する必要がある場合は、上記の理由でデータベースに配置します。

明示的に言及した場合、以前は許可されていなかったものを突然許可する場合、これは実際には問題ではありません。存在する場所に関係なく、強制された制約をすべて削除します。反対に、突然教師が学生になることを許可されなくなった場合、以前に制約がどこに存在していたかに関係なく、クリーンアップするためのデータが大量にある可能性があります。


9
  1. データベースは制約を効果的にチェックできます。コードよりも優れています。

  2. 整合性制約は、データベースが効果的な実行計画を見つけるのに役立ちます

  3. アプリケーションは読み取り一貫性のあるビューを見るため、一意性を保証することはほとんどできません。データベースはコミットされていないデータも見ることができます。


8

簡単な答え...データの整合性(正確性と有効性)を保持します。

例外...
ほとんどのSqliteデータベースのように、データベースが単一ユーザーの単一アプリケーションのデータのみを格納している場合、制約は必要ないかもしれません。実際、通常はそうではないため、アクセス時間を非常に速く保つために、測定することはできません。

他のすべてのために...
データベースは常にエディターユーザーと呼ぶ2つのマスターにサービスを提供します

編集者は主にデータベースにデータを入れて、一度に1つまたは少数のレコードのデータを取得します。主な関心事は、関連するすべてのデータへの高速で正確なアクセスと、変更の高速で信頼性の高いストレージです。

ユーザーは主にデータを取得し、間違いなく正確な情報への高速アクセスに最も関心を持っています。彼らは、緑色の紙の印刷物のそれらの象徴的な足の厚さのスタックで生成されていたが、通常は今日のウェブページに通常表示されるさまざまなカウント、集計、およびリストを必要とします。

データベース開発プロジェクトは、ほとんどの場合、ユーザーの要請で開始されますが、設計は、エディターのデータ入力とレコードごとのニーズによって推進されます。そのため、経験の浅い開発者は、多くの場合、データベースに制約を設定しないことで、(主に開発の)速度に対する差し迫ったニーズに対応します。

場合は、唯一のアプリケーションは、これまでのデータを変更するために使用されようとしている生涯データベースの、そのアプリケーションは、1つまたはウェル協調少数の個人によって開発され、可能性が頼りにするのが妥当であることデータの整合性を保証するアプリケーション。

しかし、未来を予測できるふりをすることはできますが、できません。

データベースを作成する努力は、それを捨てることができないほど貴重です。家のように、データベースは何度も拡張、変更、および改修されます。完全に置き換えられた場合でも、すべての古いビジネスルールと関係を維持しながら、すべてのデータが新しいデータベースに移行されます。

制約は、それらのルールと関係を、簡単にアクセスできるデータベースエンジン自体に簡潔で宣言的な形式で実装します。それらがなければ、後続の開発者は、アプリケーションプログラムを使用してこれらのルールをリバースエンジニアリングする必要があります。がんばろう!

これらの大規模なデータベースは、リレーショナルエンジンと制約が作成される前に作成されることが多かったため、これは、メインフレームCOBOLプログラマーがやらなければならないことです。IBMのDB2のような最新のシステムに移行したとしても、おそらく一連のCOBOL「バッチ」プログラムに組み込まれた古いルールのロジックは、変換するのが実用的でないほど複雑になるため、制約が完全に実装されないことがあります。代わりに、自動ツールを使用して、古いCOBOLを新しいリレーショナルエンジンへのインターフェイスを備えた新しいバージョンに変換し、少し調整するだけで、データの整合性が維持されます。例えば、彼らが持つべきではない何千もの住宅所有者を差し控えるために法廷に。


7

他のコメントに加えて...

特定のテーブルを1つ以上のアプリケーションまたはコードパスで更新できるデータベースがある場合、適切な制約をデータベースに配置することは、アプリケーションが「同じ」制約コードを複製しないことを意味します。これにより、メンテナンスが簡素化され(データモデルが変更された場合に変更する場所の数が減る)、データが更新されるアプリケーションに関係なく制約が一貫して適用されるようになります。


5

個人的には、たとえばトリガーを作成するよりも、制約を作成および変更する方が簡単だと思います。これは、ソースコードを使用してビジネスルールを実施する1つの方法です。

また、トリガーは通常、PL / SQLなどのベンダー固有の言語で記述されているため、移植性が低くなります。

ただし、制約がニーズを満たさない場合は、いつでもトリガーを使用してビジネスルールを実施できます。


5
また、読み取り一貫性の問題により、トリガーは整合性を保証しません。
デビッドアルドリッジ

3

常に最初にデータベースに適用する必要があります。なぜなら、

  1. データベースは、異なるクライアント間の整合性を保証します。異なるプラットフォームの異なるクライアントがデータベースにアクセスすることができます。データベースの制約により、新しいクライアントを作成するときに整合性の問題が発生するリスクはありません。これにより、書き換えまたは追加のアクセスポイントが発生した場合に制約をQ / Aする必要がなくなります。
  2. データベースには、制約を作成するためのDSLがあります:SQL DDL!
  3. データベースは、システムカタログ内のこれらの制約へのアクセスを提供するため、適切なORMまたは「スキーマローダー」がこれらの制約を読み取り、アプリケーションに取り込むことができます。たとえば、データベースにvarchar(5)タイプがあることが指定されている場合、言語タイプをスキーマのタイプにマップし、サイズの制約を独自に組み立てる特定の言語のORMをロードするスキーマを見つけることができる可能性があります。DBIx for Perl is one such schema loader; ここにEntity Frameworkの別のものがあります。これらのローダーの機能はさまざまですが、提供できるものはすべて、データベースにアクセスせずにアプリの整合性を確保するための良い出発点です。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.