そのnoobの質問で申し訳ありませんが、データベース内のテーブルと1対1の関係を使用する必要がありますか?1つのテーブル内に必要なすべてのフィールドを実装できます。データが非常に大きくなった場合でも、SELECT
を使用する代わりに、ステートメントで必要な列名を列挙できますSELECT *
。この分離が本当に必要なのはいつですか。
そのnoobの質問で申し訳ありませんが、データベース内のテーブルと1対1の関係を使用する必要がありますか?1つのテーブル内に必要なすべてのフィールドを実装できます。データが非常に大きくなった場合でも、SELECT
を使用する代わりに、ステートメントで必要な列名を列挙できますSELECT *
。この分離が本当に必要なのはいつですか。
回答:
スーパークラスとサブクラスの間の「1から0..1」は、継承を実装するための「個別のテーブル内のすべてのクラス」戦略の一部として使用されます。
「1から0..1」は、「0..1」の部分がNULL可能なフィールドで覆われている単一のテーブルで表すことができます。ただし、関係の大部分が「1から0」で、「1から1」の行が少ない場合は、「0..1」の部分を別のテーブルに分割すると、ストレージ(およびキャッシュのパフォーマンス)のメリットがいくらか節約される可能性があります。一部のデータベースは、他のデータベースよりもNULLの保存が少ないため、この戦略が実行可能になる「カットオフポイント」は大幅に異なる可能性があります。
実際の「1対1」はデータを垂直方向に分割します。これはキャッシュに影響を与える可能性があります。データベースは通常、個々のフィールドのレベルではなく、ページレベルでキャッシュを実装するため、行から少数のフィールドのみを選択した場合でも、通常、行が属するページ全体がキャッシュされます。行が非常に広く、選択したフィールドが比較的狭い場合、実際には必要のない多くの情報をキャッシュすることになります。そのような状況では、そう、縦方向にデータを分割することが有用であるだけでキャッシュ効果的に「大きな」を作り、そう、狭く、より頻繁に使用される部分または行がキャッシュされます、よりそれらのキャッシュに収まることができます。
垂直分割のもう1つの用途は、ロック動作を変更することです。データベースは通常、個々のフィールドのレベルではロックできず、行全体のみをロックできます。行を分割することにより、半分の1つだけでロックを実行できるようになります。
トリガーも通常、テーブル固有です。理論的にはテーブルを1つだけにして、トリガーに行の「間違った半分」を無視させることができますが、データベースによっては、トリガーが実行できることと実行できないことに対して追加の制限を課す場合があり、これが非現実的になる可能性があります。たとえば、Oracleでは変更テーブルを変更できません。個別のテーブルを使用することで、一方のみが変更される可能性があるため、トリガーからもう一方を変更できます。
個別のテーブルを使用すると、よりきめ細かいセキュリティが可能になります。
これらの考慮事項はほとんどの場合無関係であるため、ほとんどの場合、「1対1」のテーブルを単一のテーブルにマージすることを検討する必要があります。
2つの1対1のテーブルを1つに配置すると、セマンティクスの問題が発生する可能性があります。たとえば、すべてのデバイスに1つのリモートコントローラーがある場合、デバイスとリモートコントローラーの特性を1つのテーブルに配置するのはあまり良いことではありません。特定の属性がデバイスまたはリモートコントローラーに属しているかどうかを判断するのに時間を費やす必要がある場合もあります。
列の半分が長い間空のままであるか、埋められない場合があります。たとえば、車には多数の特性を持つトレーラーが1つある場合と、ない場合があります。したがって、未使用の属性がたくさんあります。
テーブルに20個の属性があり、そのうち4個だけがときどき使用される場合は、パフォーマンスの問題のためにテーブルを2つのテーブルに分割するのが理にかなっています。
このような場合、すべてを1つのテーブルにまとめるのは良くありません。その上、45列のテーブルを扱うのは簡単ではありません!
私の2セント。
私は私たち全員が大規模なアプリケーションで開発する場所で働いており、すべてがモジュールです。たとえば、users
テーブルがあり、ユーザーのFacebookの詳細を追加するモジュールと、Twitterの詳細をユーザーに追加するモジュールがあります。これらのモジュールの1つを取り外して、そのすべての機能をアプリケーションから削除することもできます。この場合、すべてのモジュールはusers
、次のように、1:1の関係を持つ独自のテーブルをグローバルテーブルに追加します。
create table users ( id int primary key, ...);
create table users_fbdata ( id int primary key, ..., constraint users foreighn key ...)
create table users_twdata ( id int primary key, ..., constraint users foreighn key ...)
これを使用する最も賢明な時期は、この方法でのみ関連する2つの別個の概念がある場合です。たとえば、車には現在のドライバーが1人しかいませんし、ドライバーは一度に1台の車しか運転できません。したがって、カーとドライバーの概念の関係は1対1になります。これは、ポイント。
もう1つの理由は、さまざまな方法で概念を専門化したいということです。Personテーブルがあり、従業員、顧客、株主など、さまざまなタイプのPersonの概念を追加する場合、これらのそれぞれに異なるデータセットが必要になります。それらの間で類似しているデータはPersonテーブルにあり、スペシャリスト情報はCustomer、Shareholder、Employeeの特定のテーブルにあります。
一部のデータベースエンジンは、非常に大きなテーブル(多くの行)に新しい列を効率的に追加するのに苦労しており、新しい列が元のテーブルに追加されるのではなく、拡張テーブルが新しい列を含むために使用されるのを見てきました。これは、追加のテーブルのより疑わしい使用法の1つです。
パフォーマンスや読みやすさの問題のために、単一の概念のデータを2つの異なるテーブルに分割することもできますが、これは、最初から始める場合はかなり特殊なケースです。これらの問題は後で明らかになります。
データベースの正規化について言及しています。私が管理しているアプリケーションで考えられる1つの例は、Itemsです。このアプリケーションを使用すると、ユーザーはさまざまな種類のアイテム(InventoryItems、NonInventoryItems、ServiceItemsなど)を販売できます。すべてのアイテムに必要なすべてのフィールドを1つのItemsテーブルに格納できますが、すべてのアイテムに共通のフィールドを含むベースItemテーブルを用意し、アイテムタイプ(Inventory、NonInventory、など)そのアイテムタイプのみに固有のフィールドが含まれています。次に、アイテムテーブルには、それが表す特定のアイテムタイプへの外部キーがあります。特定のアイテムテーブルと基本アイテムテーブルの間の関係は1対1になります。
以下は、正規化に関する記事です。
すべての設計の質問と同様に、答えは「状況によって異なります」です。
いくつかの考慮事項があります。
テーブルはどのくらい大きくなりますか(フィールドと行の両方の観点から)?メンテナンスとプログラミングの両方の観点から、ユーザーの名前、パスワードを、あまり使用されない他のデータと一緒に格納するのは不便な場合があります。
制約のある結合テーブルのフィールドは、時間の経過とともに管理が面倒になる可能性があります。たとえば、特定のフィールドに対してトリガーを起動する必要がある場合、そのフィールドが影響を受けたかどうかに関係なく、テーブルが更新されるたびにトリガーが発生します。
関係が1:1になることをどの程度確信していますか?この問題が指摘、物事はすぐに複雑にすることができます。
私は通常、実際には2つの一般的な1:1の関係に遭遇します。
IS-A関係。スーパータイプ/サブタイプ関係とも呼ばれます。これは、ある種類のエンティティが実際には別のエンティティのタイプである場合です(EntityAはEntityBです)。例:
これらすべての状況で、スーパータイプエンティティ(Person、Item、Carなど)はすべてのサブタイプに共通の属性を持ち、サブタイプエンティティは各サブタイプに固有の属性を持ちます。サブタイプの主キーは、スーパータイプの主キーと同じになります。
「上司」の関係。これは、個人が組織単位(部門、会社など)の一意のボスまたはマネージャーまたはスーパーバイザーである場合です。組織単位に許可されている上司が1人だけの場合、上司を表す個人エンティティと組織単位エンティティの間には1:1の関係があります。
まず、別のエンティティを構成するものをモデル化して定義することが問題だと思います。あなたがcustomers
たった一つのシングルを持っているとしましょうaddress
。もちろん、すべてを1つのテーブルに実装できますcustomer
、将来、彼に2つ以上のアドレスを許可する場合は、それをリファクタリングする必要があります(問題ではありませんが、意識的に決定してください)。
他の回答では言及されていない、テーブルの分割が役立つ可能性がある興味深いケースについても考えることができます。
繰り返しになりますがcustomers
、address
それぞれが1つであると想像してください。ただし、今回はアドレスを持つことはオプションです。もちろん、あなたはそれをたくさんとして実装することができますNULL
、これをZIP,state,street
。など-able列のます。しかし、あなたがいることを与えられたと仮定しなければならないの状態はオプションではありませんアドレスが、ZIPです。それを単一のテーブルでモデル化する方法は?customer
テーブルに制約を使用することもできますが、別のテーブルに分割して、foreign_keyをNULL可能にする方がはるかに簡単です。そうすれば、エンティティ address
はオプションであり、ZIP
はそのエンティティのオプションの属性であるという点で、モデルははるかに明確になります。
私のプログラミングの時、私は1つの状況でのみこれに遭遇しました。これは、同じ2つのエンティティ(「エンティティA」と「エンティティB」)の間に1対多および1対1の関係がある場合です。
「エンティティA」に複数の「エンティティB」があり、「エンティティB」に「エンティティA」が1つだけあり、「エンティティA」に現在の「エンティティB」が1つだけあり、「エンティティB」に「エンティティA」が1つしかない場合。
たとえば、車には現在のドライバーが1人しかいませんし、ドライバーは一度に1台の車しか運転できません。したがって、カーとドライバーの概念の関係は1対1になります。この例は@SteveFentonの回答から借りました。
ドライバーが同時にではなく、複数の車を運転できる場所。したがって、Car andDriverエンティティは1対多または多対多です。ただし、現在のドライバーが誰であるかを知る必要がある場合は、1対1の関係も必要です。