2011-06-29 18 views
1

データベースの再設計について考えてみましょう。違い/警告のようなものにしているか疑問に思う:mysqlデザイン:詳細テーブル

users address 
----- ------ 
id  id 
     user_id 
     street1 
     street2 
     etc... 

とは対照的に、

users fields 
----- ------ 
id  id 
     user_id 
     page_id 
     field_id 
     field_data 

私は考えていないよというの元を使用しての問題はありますか? fieldsテーブルが巨大になると、パフォーマンスヒットはありますか?これはちょうど悪い練習ですか?なんらかの理由で、これは私にnosqlを考えるようになりますが、私は間違っている可能性があります。

ありがとうございます!

答えて

1

あなたが表示している内容は完全にはっきりしませんが、最初のデザインでは特定のアドレス列がリストされていないと思われるので、より一般的な考え方になります。最初のデザインは簡単に拡張できます。列を追加するのではなく、新しいfield_idとフィールドデータを追加するだけです。

代わりのようなもの...あなたとそれを使用して他の人がで動作するように痛みのそれ以上を見つけること言って:

SELECT street1, street2, city, postal_code FROM address where user_id = someval 

あなたがやる:で

SELECT field_id, field_data FROM fields WHERE field_id in 
('street1', street2', 'city', 'postal_code') 
AND user_id = someval 

を最初のケースでは、プログラムで変数を結果に割り当てる方が簡単かもしれません。後者の場合は、各field_idに何が含まれているかを調べる必要があるかもしれないので、言語に応じてもう少し痛みがあります。 。

ほとんどの場合、第2のアプローチに進むべきだと思います。特に、大部分のフィールドがあらかじめわかっている場合は特にそうです。最初のアプローチは、後に知られていない多くの未知のフィールドを後で追加する必要があると思われるときに役立ちます。

3

最初に概説するアプローチは「プロパティバッグ」です。それはあなたのユーザーに対して保存される予定のデータセットに構造がないことを意味します。 2番目のアプローチは、特定のエントリを持つ特定のアドレステーブルを持つ構造化アプローチです。

実際にどのアプローチが適切かを判断するデータのタイプ。大部分の構造化されていない、または特定できないデータについては、プロパティバッグアプローチは非常に適切です。ただし、各ユーザーが確実にアドレスを持っていることがわかっていて、アドレスの構造が正確な形式になる場合は、値の特定の列を持つアドレステーブルを持つことが理にかなっています。

本当にこれらのタイプの構造が適切かどうかを判断することは、受信するデータの知識や期待、およびそれに固有の構造(存在する場合)を持つことです。私は頻繁にこれらの2つのアプローチの組み合わせを見てきました。レコードごとによく知られた構造化されたデータセットがあり、(潜在的な)広範な構造化されていない構造化データもありましたレコードに追加することはできますが、そうでないかもしれません。

編集:特にパフォーマンスの問題に対処するために、最初のケースでテーブルが大きくなるとパフォーマンスが問題になることがあります。また、表が大きくなる前であっても、実行する必要がある問合せのタイプによっては、パフォーマンスが問題になることがあります。プロパティバッグアプローチを使用すると、索引付けを使用してクエリを高速化する(たとえば、郵便番号の索引付け)ことができなくなります。

1

第二のアプローチが優れている - その理由は次のとおりです。

  1. あなたのアドレステーブル何アドレスを定義し、あなたがあなたを見つけた場合ので、それは
  2. 、アドレスを使用するすべてのテーブルを変更することなく、簡単に変更できますです1人のユーザーに複数のアドレスが必要です。それはずっと整頓されており、ユーザーにエイリアス各アドレスを許可します。 Amazonはこれを行います。ここにあなたのテーブルは次のようになります:

ここでは例のDB構造が

create table user (
user_id int, 
home_address_id, 
postal_address_id 
... 
); 

create table address (
address_id int, 
alias text, -- what the user calls this - eg "Uncle bob's house" 
street text, 
suburb text, 
... 
); 

create table sale (
sale_id int, 
user_id int, -- actually, this is not required since you can go via address, but leave it 
delivery_address_id int, 
... 
} 

だこれは、ユーザーが再利用可能な他のアドレスにコンテンツを送信させます - 多分私は常に叔父ボブにクリスマスの贈り物を送ります - 問題はありません。私は自分のピックリストに彼の住所を持っています。

+0

ありがとうございました。そうですね、データをより簡単に見つけることができる以外の理由がなければ、後者のアプローチを使用するのが理にかなっているようで、データを使って何ができるのかという点でより柔軟性があります。しかし、私がプロジェクトに着手しているので、最初のアプローチは大いにおいしく見えます;) – stormdrain

1

パフォーマンスに関する質問については、いくつか考えてください。

1つはINSERTです:auto_increment IDを使用すると、あるデータベースサーバーから複製された(特に複数のマスターの)構成に移動するときに、水平に縮尺されません。したがって、テーブルサイズは最初のアプローチで問題を早期に引き起こします。

MyISAMはINSERTとUPDATEでテーブルレベルのロックも行います。そのため、InnoDBの代わりにMyISAMを使用している場合(読み込み速度など)、最初のアプローチも問題になります。基本的に、InnoDBを使用する必要があります。

もちろん、読み込みにどのような影響があるかを検討することが最も重要です。フィールドプロパティでSELECTを実行する場合は、最初の方法を使用すると、これらの列のインデックスが大きくなることを理解してください。 ORDER BYは問題になります。クエリにORDER BY address.cityがあり、都市列にインデックスがある場合、それは2番目のシナリオではインデックスファイルのディスクからのシーケンシャル読み取りですが、まず都市以外の行をスキップします(同等のクエリはWHERE field_id = "city" ORDER BY field_dataです)。

したがって、Paulの言うとおり、ほとんどの場合、データに依存します。任意のデータセット(つまり「ロングテール」)をたくさん格納する必要がある場合は、NoSQLスタイルが適切であり、単一のデータベースサーバー上でInnoDBを使用すると、そのパフォーマンス上の短所を最小限に抑えることができます。この方法で動作するシステムを構築しました(つまり、任意のユーザー作成HTMLフォームデータを格納するため)。両方のアプローチを使用する単純なアプリケーションの例は次のとおりです。WordPress - 標準的な正規化されたリレーショナルテーブルを使用して、何度も繰り返し保存する既知のコアデータ型(ユーザー、ブログ投稿、コメント)非正規化アプローチを使用する定義済みメタデータです。

完全にの非正規化構造で高性能が必要な場合は、CouchDBやMongoDBなどのNoSQLデータベースを検討することを強くお勧めします。 MySQLとそのインデックスは、これらの種類のクエリには最適ではありません(私が説明した不連続なインデックス問題で、多くの自己結合で終わるでしょう)一方、NoSQLはプロパティベースのインデックスやネストされたサブインデックスのインデックスプロパティ。完全なMap/Reduceを実行するか、MongoDBを使用して、データレコードで実行される任意のJavascript関数の結果にインデックスを付けることができます。