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


124

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

私には1つの主キー(たとえば、ユーザーのID)があり、そのユーザーに関連付けられた大量の情報があります。

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

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

最近、そのようにしない方がいいとのコラムがたくさんあり、たくさんの列を持つテーブルを用意するのが良いと私に言いました。問題は、これらの列はすべて同じ主キーを持っているということです。

私はデータベース設計にかなり慣れていないので、どちらのアプローチがより優れており、長所と短所は何ですか?

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


わかりやすくするために、私が間違っている場合は修正してください。ただし、「複数のテーブル」はリンク/連想テーブルとして理解できると思います: en.wikipedia.org/wiki/Associative_entity
cellepo

1
このデータベースは、分析目的または運用/トランザクション処理に必要ですか?
Alexander Radev

回答:


112

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

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

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

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

反復データの方が良い場合があるため、非正規化も注意する必要があります(データを読み取るときにデータベースが実行する必要のある作業量が減るため)。データをできるだけ正規化して開始することを強くお勧めします。非正規化は、特定のクエリのパフォーマンスの問題を認識している場合にのみ行います。


お答えいただきありがとうございます。それを読んだ後、ユーザーが1対1の列を多数持っている場合の1対1の情報の状況についてお話しました。
Xavier_Ex 2012年

@Xavier_Ex-ええ、ユーザーごとに列が1つしかない場合は、巨大なユーザーテーブルを1つだけ操作するほうが簡単です(DBエンジンが最適化するのははるかに簡単です)。
ブレンダンロング

あなたの編集された投稿はより役立つ情報を提供します!一部の列が頻繁に更新される場合、それらを別のテーブルに配置する必要があるかという新しい懸念があります。たとえば、ユーザーの生年月日は更新されませんが、バックエンドトークンは一定期間後に無効になり、頻繁な更新が必要になります。パフォーマンスを向上させるために、この方法でテーブルを分離するとよいでしょうか?私はあなたが言及したウィキについて読みに行きます:)
Xavier_Ex

@Xavier_Ex-お勧めしません。必要なすべてのデータを1つのテーブルで検索できると、パフォーマンスが大幅に向上します(非正規化の記事を参照)。結合は、(1)回転ディスクでのシークを伴う可能性がある複数の場所でデータを検索する必要があるため、(2)通常、複数のインデックスとある種のマージが必要であり、(3)クエリの計画が難しくなるため、コストがかかります。時間がかかるだけでなく、クエリオプティマイザーで問題が発生する可能性も高くなります(不適切に最適化されたクエリは非常に遅くなることがあります)。
ブレンダンロング

1
MySQL InnoDBテーブルには比較的小さな長さ制限(約8000バイト)があるため、最近同じ問題に直面しました。私の問題のテーブル(非常に長い保険フォームからのデータ、100列を超える)には、すべてUTF8の複数のvarchar列があります。そのため、〜8000バイトの制限を簡単に埋め、常に「ストレージエンジンからのエラー139」が発生しました。したがって、テーブルを分割する必要がありました。(新しいバラクーダ形式でテストし、分割せずに動作しましたが、クライアントのサーバーはまだMySQL 5.0を使用しています)。
MV。

12

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

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


1
ああ別の声!それは常に素晴らしいことです。情報をくれてありがとう!テーブルを作成するときにそのことを認識していることを確認します...しかし、元々そのような低レベルのものに気付く必要があるとは知りませんでした。
Xavier_Ex 2012年

4

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

people -> rel_p2staff -> staff

そして

people -> rel_p2prosp -> prospects

人が名前と個人の詳細を持ち、スタッフはスタッフのレコードの詳細のみを持ち、見込み客は見込み客の詳細だけを持ち、relテーブルは、スタッフと見込み客にリンクする人々からの外部キーを持つリレーションシップテーブルです。

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

このリレーションのセットをクエリするには、毎回複数テーブルの結合であり、場合によっては8以上のテーブル結合です。今年の半ばまで正常に動作しており、40000人を超えるレコードが記録されて非常に遅くなってきました。

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

解決策はpeople -> staffpeople -> prospect


再構築の様子を知りたいですか?typea staffまたはaであった単一テーブルの継承に似たものを設計してしまいましたprospectか?
Coderama 2017

1
直接関係のある人->スタッフと人->見込み客と一緒に行って、魅力的で、使いやすく、クエリが高速です。
ヴラド

4

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

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


クエリ中にjsonオブジェクトを使用するときのパフォーマンスはどうですか?
dagalti

1
@dagaltiパフォーマンスは、私がそれを使用したアプリケーションでは問題ありません。私はそれを自分自身のベンチマークを行っていないが、これはあなたに使用であるかもしれない:arangodb.com/2018/02/...
moinhaque

3

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

親/子テーブルの長所は、データの整合性、インデックス経由のパフォーマンス(はい、フラットテーブルでも実行できます)、後でフィールドを追加する必要がある場合、特に必須フィールドになる場合にIMOを維持するのが簡単です。

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

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


思い出させていただきありがとうございます!したがって、私の場合は、すべてのユーザーが複数の行を持つことができないため、すべての情報フィールドが1対1である場合のみを検討しました。また、1つの要素の概念が複数の場所に存在することはできないと私が考えるので、ユーザーは同じ要素の複数のインスタンスを持つことはできません。3番目の質問については、はい、表に要素を追加する可能性がありますが、上記の要件に違反することはありません。親/子テーブルは、複数の行を1人のユーザーに関連付ける場合に適していると思いますが、この場合、ユーザーには1対1の列が多数あることが懸念されます。
Xavier_Ex 2012年

すべての要素が現在1対1である場合でも、親/子テーブルIMOを用意する必要性や要望を取り除くことはできません。変更されたデータのログを保持することは、1つの用途です。オブジェクトの遅延読み込みは別です。単一のテーブル構造にはメリットがありますが、親子のレイアウトにもメリットがあります(ただし、これを使って極端に行く人もいますが)。
ブライアン

1

ある種のデータベース設計はすでに完了しています。私にとっては、データベース管理のシステムの難しさに依存します。確かに、一意のデータを1か所だけに置くのは本当ですが、大量のレコードを持つ過度に正規化されたデータベースでクエリを実行することは本当に困難です。2つのスキーマを組み合わせるだけです。facebookやgmailなどのように維持するのが難しい大規模なレコードがあると思われる場合は、1つの巨大なテーブルを使用します。シンプルなシステムの1つのレコードセットに別のテーブルを使用します。まあ、これは単なる私の意見です。


1
「大規模なレコードを作成する場合は、1つの巨大なテーブルを使用します。」しかし、Facebook、Googleはユーザーデータを1つのテーブルに格納せず、それらを複数のテーブルとして分離します。
Yami Odymel 2018

0

これを行う従来の方法は、スタースキーマやスノーフレークスキーマのように異なるテーブルを使用することです。ハウィーヴル、私はこの戦略を2倍にすることにしました。私は、データが1か所にのみ存在するべきだという説を信じています。ただし、レポートエンジンとBIスイートの場合、レポートのニーズをよりサポートするため、円柱状のアプローチは非常に有益であると私は思います。infobright.orgを使用するような列形式のアプローチは、パフォーマンスが大幅に向上し、圧縮されているため、両方のアプローチを使用すると非常に便利です。多くの企業は、組織内のデータベースアーキテクチャが1つしかない場合、そのニーズのすべてをサポートできないことに気づき始めています。多くの企業が、複数のデータベース構造を持つという両方の概念を実装しています。


情報に感謝しますが、申し訳ありませんがあなたの答えがよくわかりません...最初に述べた2つのスキーマで検索を行います...
Xavier_Ex

-4

単一のテーブルを使用する方がより効果的だと思いますが、関係、傾向、および同じ行の変数の違いを示すようにテーブルを編成する必要があります。たとえば、表に生徒の年齢と学年が表示されている場合は、最高得点と最低得点が明確に区別され、生徒の年齢の差が均等になるように表を並べます。

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