web-dev-qa-db-ja.com

スキーマレスデータをリレーショナルデータベースに効率的に格納する方法

検索可能性と速度のバランスをうまく取ろうとしています。私はさまざまな方法で実験しています。

オプション1:配列をJSON/PHPシリアル化配列としてシリアル化し、「メタ」列に保存します。

   id  |  name   | meta  
1       Bob       {"city":"GoTown","birthdate":"1980\/8\/14","cat":"Felix"}
2       Alice     {"city":"Streamville","birthdate":"1986\/6\/6","dog":"Rex"}

オプション2:キーと値を一緒にスタックに格納します。

user_id  |    key   |   value   
1         name       Bob
1         city       GoTown
1         birthdate  1980/8/14
1         cat        Felix
2         name       Alice
2         city       Streamville
2         birthdate  1986/6/6
2         dog        Rex

オプション3:3つのテーブル:エンティティ、キー、値。各キー名は一度だけ保存してください。

user_id  |   name   
1         Bob
2         Alice

key_id   |   keyname   
1         city
2         birthdate
3         cat
4         dog

user_id   |   key_id   |   value
1          1            GoTown
1          2            1980/8/14
1          3            Felix
2          1            Streamville
2          2            1986/6/6
2          4            Rex

これらの戦略のいずれかを使用する場合の落とし穴はありますか?それらが乗り越えられない不利な点を持っているなら、私はそれらのいくつかを排除したいと思います。

編集:スキーマなしのデータを表すためにいくつかのデータを追加しました

7
techturbulence

これらのテーブルでいくつかの本当に厄介な問題が発生します(アイデア)

  1. データの冗長性(重複データ)同期を維持するために必要なもの(そして、MySQLにはレコード機能のある素敵なJSONがないため、これを確認しますか?)

  2. データベースに正しい値を強制することはできません(データの完全性に別れを告げ、ガベージインガベージアウトデータにhelloする)サンプルキーの生年月日の値は "hello"

そして、あなたはキー/値をフェッチするためにある種のピボットクエリが必要です

動的キー値(EAV)ストレージが本当に必要な場合は、さらにいくつかのオプションがあります。

3
Raymond Nijland

あなたのサンプルデータから私は実際にテーブルのスキーマを見る

UserID | UserName | City | Birthdate

正しい索引付けでリレーショナルデータベースを使用している場合、その検索は非常に高速になります。一部の値がnullになる可能性がある場合は、null許容列を許可します。

キーバリューストアは状況に応じて最適ですが、データの検証に関して非常に煩雑になる可能性があります。リレーショナルデータベース製品を使用している場合は、それを機能させ、適切に型指定された列を使用して入力側で検証を実行します。

本当にキーバリューストアを使用したい場合は、それらに最適化されたNoSQL製品がおそらくより良い方法です。

3

あなたの要件(MySQLと「スキーマレス」)を考えると、ひねりを加えたオプション1を検討する価値があると思います。 JSONではなくXMLを検討してください。

どうして? MySqlはJSONを処理する簡単な方法を提供しませんが、xmlを使用するためです。

このことを考慮:

id  |  name   | meta  
1      Bob      <city>GoTown</city><birthdate>1980-08-14&</birthdate>
2      Alice    <city>Streamville</city><birthdate>1986-06-06<birthdate>

これで、メタフィールドのコンテンツに対してxpath式を使用してSQLクエリを実行できます。そのようです:

SELECT name, extractValue( meta, '//birthdate' ) as birthdate
from tbl

都市に基づいて選択を行うこともできます(もちろん、where句に一致するフィールドの内容を解析する必要があるため、これは非常に非効率的です)。

SELECT name<BR>
from tbl<br>
where id < 100
having extractValue( meta, '//city' ) = 'Streamille'

また、UpdateXML(別のMySQL関数)を使用して、すべてのMySQL内でフィールドのコンテンツを変更することもできます。

私の返答が遅れていることはわかっていますが、誰かがこれが役に立つ/興味深いものであることを誰かが見つけてくれることを願っています。 :)

3
Wendell Brown

コミュニティwikiの回答

PostgresはMySQLよりも多くのNoSQL機能を備えています。 JSON実装ははるかに効率的であり(JSONドキュメントにインデックスを付けることができます)、非常に効率的なキー/値ストア(インデックスも可能)を備えています。 Postgresはおそらく最も高度な「NoSQLリレーショナルデータベース」です。

2
user126897

MySQLにjsonデータを保存することもできます。MySQL5.7はjsonデータをネイティブでサポートしています。

mysql json data type を参照してください

誕生日が08/10から08/17までのすべての顧客を紹介する必要がある場合、オプション1は適していません。

オプション2と3は似ています。テキストではなく整数コードで検索またはグループ化するのが好きなので、個人的にはオプション3を好みます。

ところで。月と日を2つの数値として保存することをお勧めします。次に、それらを文字列として並べ替えることができますが、それでも正しくなります。1970/ 10/10は1970/08/08より後ですが、1970/8/8より前です。

1
Alex

MySQLの使用にしっかりと慣れていない場合は、DB2をオプションとして検討できます。 JSONデータをネイティブでサポートしているため、JSONフラグメントを簡単に照会および操作できます( http://publib.boulder.ibm.com/infocenter/db2luw/v10r5/topic/com.ibm.swg.im .dbclient.json.doc/doc/c0061316.html )。

別の代替手段はXMLです。繰り返しになりますが、DB2は、クイック検索のためのXPath式の索引付けを含め、それをネイティブでサポートしています。 ( http://publib.boulder.ibm.com/infocenter/db2luw/v10r5/topic/com.ibm.db2.luw.xml.doc/doc/c0022308.html

DB2 Express-Cは無料版で、本番環境での使用やデータベースサイズに制限はありません。

1
mustaccio