この場合の外部キーの必要性(innoDB/mysql)
-
05-07-2019 - |
質問
最近、DB全体をmyisamからinnodbに移行しました。私はこれについてはかなり初心者なので、外部キーの使用について質問があります。
2 つのテーブルがあるとします。ユーザー、メッセージ。
ユーザー
id (pr_key)
name
メッセージ
id (pr_key)
user_id
message
ID フィールドは両方とも自動的にインクリメントされます。
したがって、私のクエリでは、これらの 2 つのテーブルをすでに結合しています。ここに外部キーを配置する必要がありますが、実際には意味がありません。パフォーマンス上の利点はありますか。
ここに外部キーを置くことを選択した場合、メッセージの pr_key を id と user_id の両方にする必要があると想定します。
他の prim_key を追加すると、より多くのスペースが必要になるだけでなく、パフォーマンスが低下します。
ここで、テーブルに 2 つの pr_key があり、そのうちの 1 つに対してのみクエリを実行した場合でも、同じパフォーマンスの利点が得られます。それとも、2 つのキーを明示的に使用する必要がありますか。
この例では user_id で検索することになるので、とにかくこれにインデックスを付けるのが賢明かもしれません。しかし、そのフィールドが検索が行われていないフィールドである場合はどうなるでしょうか。外部 hey リレーションのためだけに、このフィールドに複数の主キーを配置するのはまだ良いでしょうか。
ありがとう!
解決
データの整合性 の利点があります。
idが1234のユーザーがuserテーブルにない場合、アプリケーションコードがメッセージテーブルに1234のuser_idを入力するのを停止します。また、ユーザーがメッセージテーブルにメッセージを持っている場合、アプリケーションがユーザーを削除しないようにします。
PKの名前は、参照する子テーブルのFKの名前と一致する必要はありません。
"ここに外部キーを配置することを選択した場合、メッセージのpr_keyをidとuser_idの両方にする必要があると仮定します。 "
いいえ 。メッセージテーブルのキーを変更するのではなく、メッセージテーブルのUser_Id列に外部キー(FK)制約を設定します。これは、ユーザーテーブルのid列を参照(ポイント)します。メッセージにPKを追加する必要はありません。PKは既に一意であるため(同じmessageIdのメッセージを2つ持つことはできません)、IDとuser_idの両方でPKを使用して一意性を追加することはできません。)
ここで一番下の行は、主キーと外部キーが実際に何であるかについて基本的な誤解があるかもしれないということです。
- PKは行の一意性に対する制約であり、インデックスが必要です。
- FKは、列の値に対する制約です(値は、参照される他のテーブルにPK値として存在することを義務付けています)。インデックスは必要ありません。
@Noah、その他の質問
他のヒント
メッセージ (user_id) に対して正式な FOREIGN KEY ルールを確立するかどうかに関係なく、単純な事実として、これは外部キー関係です。
まず、テーブル内の各レコードを一意に識別するには、テーブル上の適切な主キーで十分であることを覚えておいてください。各メッセージにはすでにそれが含まれていることを考慮すると、 id
フィールドをラップする必要も、特にラップする必要もありません。 user_id
メッセージテーブルの主キーに入力します。
第二に、チャールズがすでに述べたように、users(id) を参照するメッセージ (user_id) で FOREIGN KEY を宣言すると、データの整合性を確保できるようになります。外部キー制約を使用すると、メッセージ テーブルに対応するレコードがあるユーザー テーブルのレコードが削除されたときの動作を指定できます。選択肢は、ON DELETE CASCADE (このユーザー レコードのすべての子レコードを削除する)、ON DELETE RESTRICT (メッセージ テーブルにレコードを持つユーザーの削除を許可しない)、ON DELETE NO ACTION (削除操作を無視する) です。 , ON DELETE SET NULL (子レコードは保持しますが、user_id フィールドを NULL に設定します)。
これらのオプションはそれぞれ状況に応じて適切ですが、ここで最も重要なことは、子テーブルから親テーブルへの予期しない null ポインターを防止できることです。
3 番目に、FOREIGN KEY 関係を確立すると、users テーブルの PRIMARY KEY に対応するメッセージ (user_id) の INDEX が生成されるため、パフォーマンスが向上します。これらのフィールドを結合するクエリを実行すると、FOREIGN KEY を設定しない場合と比較して、子レコードを返すためにクエリを実行する必要があるレコードの数が大幅に減少していることがわかります。
@Charles Bretana - リンク先の質問は、Microsoft SQL Serverに固有のものです。ここでの質問は MySQL / InnoDB に関するものです。
のドキュメントを参照することをお勧めします InnoDB の外部キー制約.
INNODBには、外部キーの鍵と参照キーのインデックスが必要なため、外部キーチェックが高速になり、テーブルスキャンが必要になります。参照表には、外部キー列が最初の列として同じ順序でリストされるインデックスが必要です。このようなインデックスは、存在しない場合、参照テーブルに自動的に作成されます。(これは、インデックスを明示的に作成する必要がある、または外部のキー制約の作成が失敗する場合、いくつかの古いバージョンとは対照的です。)index_nameは、前述のように使用されます。