web-dev-qa-db-ja.com

MySQL:複数のテーブルまたは複数の列を持つ1つのテーブル?

したがって、これは設計上の問題です。

主キー(ユーザーのIDなど)が1つあり、そのユーザーに関連する情報がたくさんあります。

情報に応じて複数のテーブルをカテゴリに分類する必要がありますか、それとも多くの列を持つ1つのテーブルだけが必要ですか?

以前は、アプリケーションの使用状況データ用の1つのテーブル、プロファイル情報用の1つのテーブル、バックエンドトークン用の1つのテーブルなど、整理された状態を保つために複数のテーブルを使用していました。

最近、そのようにしない方が良いと私に言われ、多くの列を持つテーブルを持っていることは良いことです。重要なのは、これらの列はすべて同じ主キーを持っているということです。

私はデータベース設計にかなり慣れていないので、どちらのアプローチが優れているか、また、賛否両論は何ですか?

それを行う従来の方法は何ですか?

107
Xavier_Ex

情報が1対1である場合(各ユーザーが1つの名前とパスワードを持っている場合)、結果を取得するためにデータベースが行う必要のある結合の数を減らすため、1つのテーブルを保持する方がおそらく良いでしょう。一部のデータベースではテーブルごとの列数に制限があると思いますが、通常は心配しません。必要に応じて後からいつでも分割できます。

データが1対多の場合(各ユーザーが数千行の使用情報を持っている場合)、データを個別のテーブルに分割して重複データを削減する必要があります(重複データはストレージスペース、キャッシュスペースを浪費し、データベースのメンテナンスが難しくなります) )。

データベースの正規化 に関するWikipediaの記事は、この理由を詳細に説明しているため、興味深いかもしれません。

データベースの正規化は、リレーショナルデータベースのフィールドとテーブルを整理して、冗長性と依存性を最小限に抑えるプロセスです。通常、正規化では、大きなテーブルを小さな(および冗長性の低い)テーブルに分割し、それらの間の関係を定義する必要があります。目的は、1つのテーブルでフィールドの追加、削除、および変更を行い、定義された関係を介してデータベースの残りの部分に伝播できるようにデータを分離することです。

非正規化 も注意する必要があります。なぜなら、データを繰り返すときにデータベースが行う必要のある作業量を減らすため、データを繰り返すほうが良い場合があるからです。データをできる限り正規化して開始することを強くお勧めします。特定のクエリのパフォーマンスの問題を認識している場合にのみ非正規化してください。

97
Brendan Long

多くの場合、1つの大きなテーブルは適切ではありません。関連テーブルは、リレーショナルデータベースが機能するように設計されたものです。適切にインデックスを作成し、パフォーマンスクエリの作成方法を知っていれば、それらは正常に実行されます。

テーブルの列が多すぎると、データベースが情報を保存しているページの実際のサイズに問題が発生する可能性があります。レコードがページに対して大きすぎる可能性があり、特定のレコードを作成または更新できずにユーザーを不幸にするか、特定のオーバーフローを(少なくともSQL Serverで)許可する可能性があります。データ型(これを行う場合はルックアップする必要がある一連のルールを使用)が、多くのレコードがページサイズをオーバーフローする場合、パフォーマンスに大きな問題を引き起こす可能性があります。 MYSQLがどのようにページを処理するか、潜在的なページサイズが大きくなりすぎるときに問題があるかどうかは、そのデータベースのドキュメントで調べる必要があります。

12
HLGEM

良い例があります。次の一連の関係を持つ過度に正規化されたデータベース:

people -> rel_p2staff -> staff

そして

people -> rel_p2prosp -> prospects

人には名前と人の詳細があり、スタッフにはスタッフレコードの詳細のみがあり、プロスペクトにはプロスペクトの詳細のみがあり、relテーブルはスタッフとプロスペクトにリンクしている人からの外部キーを持つ関係テーブルです。

この種の設計は、データベース全体に適用されます。

このリレーションのセットを照会するには、毎回複数テーブルの結合、時には8つ以上のテーブル結合が必要になります。今年の半ばまでは正常に動作していましたが、40000人を超えるレコードが記録され、非常に遅くなり始めました。

インデックス作成とすべての低品質の果物は昨年使用されていたため、すべてのクエリは完璧に最適化されています。これにより、特定の正規化された設計と管理の道のりは終わり、6か月間にわたってデータベースの再構築だけでなく、それに依存するアプリケーション全体の再構築が承認されました。 $$$$痛い。

解決策は、people -> staffpeople -> prospectに直接関係を持たせることです。

4
Vlad

これに出くわし、MySQLをよく使用し、最近Postgresに切り替えた人として、大きな利点の1つは、PostgresのフィールドにJSONオブジェクトを追加できることです。

したがって、このような状況にある場合、多くの列を持つ1つの大きなテーブルとそれを分割することを必ずしも決定する必要はありませんが、列をJSONオブジェクトにマージして削減することができます。アドレスが5列である代わりに、1列だけにすることができます。そのオブジェクトに対してもクエリを実行できます。

4
moinhaque

すべてを1つのテーブルに入れる場合、これらの質問を自問してください。そのユーザーには複数の行がありますか?ユーザーを更新する必要がある場合、監査証跡を保持しますか?ユーザーはデータ要素の複数のインスタンスを持つことができますか? (たとえば電話番号など)、後で要素または要素のセットを追加する場合がありますか? 「はい」と答えると、おそらく外部キー関係を持つ子テーブルが必要になります。

親/子テーブルの長所は、データの整合性、インデックスを介したパフォーマンス(フラットテーブルでも可能)、後でフィールドを追加する必要がある場合(特に必須フィールドになる場合)の保守が容易になることです。

短所の設計は難しく、クエリは少し複雑になります

しかし、1つの大きなフラットテーブルが適切な場合が多いため、状況を確認して決定する必要があります。

3
Brian

既に何らかのデータベース設計を行っています。私にとっては、データベース管理を備えたシステムの難しさに依存しています。ええ、一意のデータが1か所にしか存在しないのは事実ですが、大量のレコードを含む過度に正規化されたデータベースでクエリを実行するのは本当に困難です。 2つのスキーマを結合するだけです。 facebookやgmailなどのように維持するのが難しい大量のレコードがあると思う場合は、1つの巨大なテーブルを使用します。そして、単純なシステムの1セットのレコードに異なるテーブルを使用します...これは私の意見です..私はそれが役立つことを願っています。

1
christopher

これを行う従来の方法は、スタースキーマまたはスノーフレークスキーマのように異なるテーブルを使用することです。しかし、この戦略は2つの要素に基づいています。データは1つの場所にのみ存在する必要があるという理論を信じており、そこで言及したスキーマはうまく機能します。ただし、レポートエンジンおよびBIスイートの場合、レポートニーズをより支援するため、円柱アプローチが非常に有益であると考えています。 infobright.orgを使用するようなカラムナーアプローチには、パフォーマンスの大幅な向上と圧縮があり、両方のアプローチを非常に便利に使用できます。多くの企業が、組織内にデー​​タベースアーキテクチャを1つだけ持っているだけでは、ニーズのすべてをサポートしていないことに気付き始めています。多くの企業が、複数のデータベースアーキテクチャを持つという両方の概念を実装しています。

0
Craig Trombly