外部キー設計のIDの増分とフルテキストキーのトレードオフは何ですか?


8

多くのリレーショナルデータベース設計には、他のテーブルで参照されるフィールドがあります。

たとえば、一意のユーザー名を持つユーザーテーブルと、アドレスデータを格納する2番目のテーブルについて考えます。

私が言えるレイアウトの1つは、ほとんどのソフトウェアで観察されているため、次のような自動インクリメントIDを使用するという一般的なアプローチです。

Table users
===========
userId int primary auto_increment
userName varchar unique

Table adressdata
==========
userId int references users.userId
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userId,adress_type))

これが以前のやり方であり、ほとんどの場合私はそれを見てきました。

別の方法は次のとおりです。

Table users
===========
userName varchar primary

Table adressdata
==========
userName varchar references users.userName
adress_type varchar // for example country
address_value varchar // for example US
(you probably also want to put a unique key on (userName,adress_type))

ここでも、完全なユーザー名をadressdataテーブルに格納します。

私にはこれには次の利点があります:

  • 別のテーブルに結合する必要なく、テーブルからすぐにユーザー名を選択できます。この例では、これはおそらくアプリケーションの観点からはあまり関係がありませんが、単なる例です。

  • auto_incrementの競合がないため、マスターマスターレプリケーション環境でデータベースをスケーリングする方が簡単な場合があります。

しかし、欠点もあります:

  • 2番目のテーブルのフィールドのインデックスとデータ(ただし、関連性が高いのはおそらくインデックス)のスペース要件が高くなります。
  • ユーザー名を変更すると、すべてのテーブルに反映される必要があります。これは、1つのテーブルでユーザー名を変更してIDをそのままにするよりも、多くのリソースを消費します。

私の意見では、テキストフィールドを操作してインクリメントIDを使用しない方がはるかに簡単です。トレードオフは最小限であり、ほとんどのアプリケーションでは関係ありません。

もちろん、いくつかのオブジェクトはその性質上、増加する番号で識別されます(たとえば、フォーラムの投稿には、タイトルなどの一意のフィールドがおそらくないため、増加するIDを受け取る必要があります)。

しかし、まったく異なる方法でデータベースレイアウトの設計を開始する前に、私が考えていないことがあるかどうかを知りたいと思います。

  • ベストプラクティスはありますか?

  • 私が考えていなかった長所/短所はありますか?その効果は後の時点で発生する可能性がありますか?

  • 上記の点に関してデータベースをどのように個人的に設計しますか、またその理由は何ですか?

回答:


3

ユーザー名ではなく、IDを使用することをお勧めします。ユーザー名を複数のテーブルの結合列として使用し始めた場合は、すべてを更新することを忘れないでください。

usersテーブルの外部キーがテーブルの主キーになり、主キーはaddressdata安定したままである必要があります。主キーフィールドを変更しないことをお勧めします。主キーは、レコードの作成時に存在している必要があり、レコードの存続期間全体にわたって変更されないままである必要があります。

さらなる洞察が必要な場合主要な主要な議論は優れた記事です。


2

私は「ナチュラルキーを使用しない」というキャンプに強く参加しています。それは、システムが更新され、事実上あらゆる種類の名前に関係するすべての自然キーが更新されるときに、システムがどれほど難しいかを見てきました。

データベースは、結合を使用するように最適化されています。はい、自然キーを使用して一部の結合を保存できますが、1,000,000レコードを更新する必要がある場合、パフォーマンスが低下します。これは、変更された自然キーのグループが(または発生している状況によっては)大きなログジャムになる可能性があるためです。

私は2つの条件の下でのみ自然キーを使用します。

  1. キーが変更されないことがかなり保証されている場合(自動車のVIN番号を考えてください)、および
  2. それが再利用されることは決してない場合(電話番号や電子メールなどのユニークなものでも、誰かが使用をやめると再利用されるため、PKの候補にはなりません)。

そしてもちろん、一意であると思われるあまりにも多くの自然キーはそうではありません。レプリケーションが心配な場合は、GUIDを使用できます。


1

サロゲートキーに関するWikipediaの記事には、いくつか興味深い点が散在しています。

  • " エンティティを一意に識別する属性が変更され、自然な複合キーの適合性が無効になる可能性があります。 "たとえば、後でユーザー名を制限すると、自然キーを使用するときに既存のキーが無効にuser nameなることがありますが、これは合成キーには影響しません。
  • 行が存在する間、代理キーは変更されません。」したがって、キーの変更を参照テーブルに(手動または自動で)カスケードする必要はありません。
  • 生成されたサロゲートキーの値は、連続して保持されるデータの実際の意味とは関係ありません」これは監査を困難にする可能性があります。

注意深い読者は、考慮すべき追加のポイントを見つけることができると思います。


いい答えです。多くの自然キーは変化する傾向があります。そのため、外部キーとして参照される可能性のあるキーには適していません。ユーザーのユーザーIDを変更することが適切である理由は多数あります。
BillThor

1

私の経験から投稿しますが、これはおそらく、さまざまなDBAの提案とは大きく異なります。私は主に、さまざまなプロジェクトのデータベースを設計する際に、パフォーマンスと保守性の混合を重視しています。

私は思います決して、これまで主キーの自然キーを使用します。特にMySQL / InnoDBを使用している場合。自然キーを使用するメリットはまだ見ていませんが、通常、パフォーマンスへの影響は何もありません。私のプロジェクトのパフォーマンスを独占するために自然なキーが使用されたという理由だけで、私は「決して、これまでに」太字にしませんでした。サロゲート(整数)は常により良い選択でした。一部は同意しないかもしれませんが、私たちはパフォーマンスが理論よりも役割を果たす世界に住んでいます。

結合に関しては、絶対に回避しようとはしませんが、最適化する傾向があります。InnoDBのクラスター化インデックス(主キー)をできるだけ乱用しようとしています。結合がPKを介して実行される場合、それらは非常に高速です。また、意味のないFKは避ける傾向があります。正直なところ、ユーザーとそのアドレス情報をリンクすることに関しては、データの整合性についてあまり気にしません。請求書をユーザーへのアイテムにリンクするときに適用します。FKの使い過ぎはやり過ぎであり、すべてを参照した後も維持するのは悪夢です。ある時点で状況が変化する必要があり、MySQLが常にエラー150で不平を言い始めたら、家に帰りたいだけです。

また、auto_incrementsの性質によるレプリケーションとクラッシュの回避についても説明しました。製品の販売情報を格納するデータベースの数が多いプロジェクトがありましたが、データベースの量はさまざまでした。データベースは毎日、レポートを実行するために使用した1つの「マスター」データベースに複製されました。PKの衝突を回避する方法は、auto_increment部分と、レコードがどこから来たかを示す別のINT部分から複合主キーを作成することでした。そうすれば、どこから来たのかを追跡でき、何も失うことはありませんでした(製品のIDは同じで、ロケーションIDのみが変更されました)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.