web-dev-qa-db-ja.com

多数の列を持つデータベース設計の最良のアプローチは何ですか?

私はクエリベースの金融アプリケーションを書いています。これにより、ユーザーは(SQLクエリのWHERE部分のように)複雑な方程式を記述し、それらの基準に一致する会社を見つけることができます。

上記について、現在データベーステーブルには500を超える列があります(各列は財務フィールドを表します)。

列の例は、company_name、sales_annual_00、sales_annual_01、sales_annual_02、sales_annual_03、sales_annual_04、protit_annual_00、profit_annual1 ...(500以上の列)です。

行数は約5000です。

今後は、さらにコラム・ファイナンシャルフィールドを増やしていきたいと思います。

上記について、私は以下について助けを求めたい:

1)最良のデータベース設計アプローチは何ですか?これらの数の列があっても問題ありませんか?

2)どのように正規化できますか? (ユーザーはこれらのフィールドのいずれかを検索条件で使用できます)。

3)MySQLを使用しても問題ありませんか、それとも、MongoDBなどの最新のドキュメントベースのデータベースの方が適していますか?

追伸(更新):私はこれまでMySQLを使用しており、使用方法の実行例は次のとおりです http://screener.in/companies/89/Formula-- 上記の約500フィールド/列を使用してクエリを作成しますが、今後はその数をさらに増やす予定です。

7
Pratyush

このサイトをアドホックレポートに使用する予定で、行数が多いことが予想される場合は、データベースを Data Warehouse として設計する必要があります。これにより、焦点が正規化からパフォーマンスとクエリの効率に移ります。これは、先ほど説明したアプリケーションに適しているようです。

この詳細については、 次元モデリング を参照してください。数値データを表す多数の列を持つこれらのテーブルは、おそらく ファクトテーブル であり、より小さく、より記述的なテーブルはディメンションです。これについての詳細 ここ

そして、私が投稿したリンクのテーマに気付かなかった場合のために、 Ralph Kimball は、データウェアハウスの設計、実装、および保守に関する数多くの優れた情報を公開しています。彼のものを読んでください!

10
CFL_Jeff

エンティティに本当に多くの異なる側面がある場合は、多くの列があっても問題ありません。しかし、sales_annual_01、sales_annual_02などは、単に「悪いデザイン」と叫びます。本質的に同じ属性の複数のバージョンがある場合、ほぼ確実にそれらは必要に応じてテーブルに結合できる別のテーブルにある必要があります。そうすることで、パワー内でロジックの未知の数の場所を更新する必要がなくなります。 5年間のレポートではなく、突然7年間のレポートが必要になります(最終的には知っている彼らはそうするでしょう)。

(CFL_Jeffが疑うシナリオがある場合、これはそれほど重要ではありません。データを変更しない場合、正規化はそれほど重要ではありませんorスキーマとパフォーマンスが最も重要な要件です。 )

12
Kilian Foth

この分割をテーブルに試してください:

Companies
(
    CompanyPK PK,
    Name
)

Sales
(
    CompanyPK PK,
    Year PK,
    Value
)

Expenses
(
    CompanyPK PK,
    Year PK,
    Value
)

この方法では、会社ごとに複数の年を持つことができ、一部の会社は特定の年に存在しなかった可能性があることを考慮に入れます。また、毎年データを移動する必要はありません。行を追加するだけです。

利益は計算(Sales = Expenses)になるため、そのためのテーブル/列は必要ありません。

多くの異なる非計算フィールドがある場合は、代わりに辞書アプローチを検討してください...

Companies
(
    CompanyPK PK,
    Name
)

Fields
(
    FieldTypePK PK,
    CompanyPK PK,
    Year PK,
    Value
)

FieldTypes
(
    FieldTypePK PK,
    Name
)

2番目のオプションの使用例:

select
    c.CompanyPK,
    c.Name
from Companies c
inner join Fields f1
on f1.CompanyPK = c.CompanyPK
inner join Fields f2
on f2.CompanyPK = c.CompanyPK
where f1.FieldPK = 1 and f1.Year = 2012 and f1.Value > 1000000
and f2.FieldPK = 2 and f2.Year = 2012 and f2.Value < 50000
3
Danny Varod

私があなたを正しく理解している場合、このデータは定期的に作成され、エンドユーザーによって読み取り専用のデータソースとして使用されます。したがって、重要な要件は、ユーザーが簡単に報告できる構造にすることです。

上記が当てはまると仮定します。この場合、正規化は重要ではないと言って、あなたは良い仕事をしています。私は、ユーザーに1つの巨大なテーブルを与えて、彼の人生を楽にします。 (#2は取り消しできます)

NoSQL(MongoDB)に移行すると、非技術系ユーザーの生活が生き生きとするようになります。5000行しかないため、パフォーマンスの問題が発生することはありません(#3を取り消して、MySQLに固執することができます)。

したがって、残っているのは、列が多すぎるという問題です。正直なところ、私がとるアプローチではありません。しかし、それほど大きな問題ではありません。

Yearenter code hereを列にしてから、sales_annualprofit_annual ect ..の静的な列のセットを列にします(ただし、ユーザーがこれを気に入らない可能性があるので、彼または彼女のこぶしに話しかけてください。)

1
Morons

1)最良のデータベース設計アプローチは何ですか?これらの数の列があっても問題ありませんか?

2)どのように正規化できますか? (ユーザーはこれらのフィールドのいずれかを検索条件で使用できます)。

これはひどいデータベース設計です。最も明白な修正は、それを 第3正規形 にする必要があることです。

Companies (
company_name,
...
)

FinancialResults (
period, 
sales_annual,
profit_annual,
...
)

[〜#〜] eav [〜#〜] スタイルのアプローチは、いくつかの回答で見ることができますが、ほとんどではありません効率的な方法であり、データを抽出するための裏側で苦痛になります。

3)MySQLを使用しても問題ありませんか、それとも、MongoDBなどの最新のドキュメントベースのデータベースの方が適していますか?

はい、MySQLはそのために完璧に動作します。 SQLなしのソリューションを検討する必要があるのは、データのタイプ、ボリューム、スループットではありません。また、任意の列に対してクエリを実行できる場合、非SQLソリューションは効率的に動作しません

1
vartec

1行あたり500フィールドで5000行の場合、リレーショナルデータベースを使用する唯一の理由は、すべてのユーザーがSQLを使用してクエリを実行する方法を知っており、生のSQLを提供することを計画していることです。

生のSQL以外に検索を実行するように彼らに指示した瞬間、DBMSを捨てて、これをフラットテキストファイルでの連続したワンパススキャンにするほうがはるかに良いでしょう。 5000 x 500 = 2.5e6なので、250万の個別フィールドがあります。フィールドあたりの平均バイト数を10とすると、2,500万バイトになります。これは、1台のPC上のメモリ常駐配列であり、最初に吸盤をメモリに読み込むと、あなたを殺します。フィールドあたりの平均バイト数を100とすると、それでもまだ2億5000万バイトに過ぎません。たぶん、あなたはそれをページングして、一気に5000万バイトです。

データがあるからといって、データベース管理システムを使用する必要があるわけではありません。

0
John R. Strohm

正規化された構造に切り替えます。 SQLは、基本的にこの設計の選択に統合されています。順守しないと、問題が発生します。ユーザーがSQLを本当に理解していて問題がないか、またはフロントエンドが負担をかけて、これらのすべての列が正規化されているという事実を隠す必要があります。

次に、UUIDを使用します。これにより、異種のデータをオンザフライで接続する際の大量の悲しみを防ぐことができます。また、検索条件はユーザーの要求に適合します。彼らが会社Fooの2010年のすべてのレコードを必要とする場合、それは会社名= Fooの会社テーブルのレコードテーブルの内部結合であり、年= 2010の年テーブルの内部結合です。

最後に、SQL設計(項目1を参照)を壊さないので、適切な設定でパフォーマンスが非常に速くなります。 SQLはすべてsetsに関連しているため、項目2の例のようなクエリの設定は非常に高速に動作します。すべてが1つの大きなテーブルにある場合、フロントエンドは突然、ネットワーク全体で(= /// =)単一の行が返されるのを待つ必要があります、それから単一の行を読み取り、検索条件と照合する必要があります。これは手続き型プログラミングではありません。ふりをしないでください。

このすべてに関する優れた投稿については、 この記事を読む です。

0
Spencer Rathbun