MYSQL 5.7のネイティブJSONサポート:MYSQLのJSONデータ型の長所と短所は何ですか?


113

MySQL 5.7では、MySQLテーブルにJSONデータを格納するための新しいデータ型が追加されました。それは明らかにMySQLの大きな変化になるでしょう。彼らはいくつかの利点を挙げました

ドキュメントの検証 -有効なJSONドキュメントのみをJSON列に格納できるため、データの自動検証を取得できます。

効率的なアクセス -さらに重要なことに、JSONドキュメントをJSON列に格納すると、プレーンテキスト値として格納されません。代わりに、オブジェクトメンバーと配列要素にすばやくアクセスできるようにする最適化されたバイナリ形式で保存されます。

パフォーマンス -JSON列内の値にインデックスを作成することにより、クエリのパフォーマンスを向上させます。これは、仮想列の「機能インデックス」で実現できます。

利便性 -JSON列の追加のインライン構文により、SQL内にドキュメントクエリを統合することが非常に自然になります。例(features.featureはJSON列です):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

うわー !彼らはいくつかの素晴らしい機能が含まれています。データの操作が簡単になりました。より複雑なデータを列に格納できるようになりました。したがって、MySQLはNoSQLでフレーバーされています。

JSONデータのクエリは次のようになります。

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN 
( 
SELECT JSON_EXTRACT(data,"$.inverted") 
FROM t1 | {"series": 3, "inverted": 8} 
WHERE JSON_EXTRACT(data,"$.inverted")<4 );

それで、いくつかのjsonカラムに巨大な小さな関係を保存できますか?いいですか?それは正規化を壊しますか?これが可能であれば、MySQLカラムではNoSQLのように動作すると思います。この機能についてもっと知りたいです。MySQL JSONデータ型の長所と短所。


ああ、あなたが言っていると思うことを言わないでください。ここを読んでください。あなたのものは悪い考えのさらに別の変種です。
2015

@Drewあなたは大きな答えを出しました。しかし、それは私の質問ではありません。私が知りたいのは、jsonデータのクエリを作成する場合、SQLルールをスキップできることです。多くのテーブルは必要ないため
Imran 2015

1
あなたが言ったNow it is possible to store more complex data in column。注意してください
ドリュー

2
Jsonデータ型のサポートインデックスとスマートサイズ:64Kおよび4G。では、2000データを保存し、リレーション付きの5つのテーブルではなく5つのネストされたラベルを追加したい場合、どのような問題がありますか?
Imran 2015

5
「私は本当にこの機能についてもっと知りたいです。」および「MySQL JSONデータ型の長所と短所」質問ではなく、質問が広すぎると言い換えると 「MySQLで複雑なスキーマ構造と外部キーを考えることはありません。いくつかのテーブルのみを使用して複雑な関係を保存します。」JSONは関係とFKではないため、自己矛盾しています。「これは良いですか」の説明は、リレーショナルモデルの紹介にすぎないため、ここでも広すぎます。いくつかの例に取り組み、参照を使用して独自の長所と短所のリストを作成し、どこが間違っていたかを尋ねます。
philipxy 2017

回答:


57
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

このような式または関数内で列を使用すると、クエリを最適化するためにインデックスを使用するクエリの可能性が損なわれます。上記のクエリは、テーブルスキャンを実行する必要があります。

「効率的なアクセス」についての主張は誤解を招くものです。つまり、クエリがJSONドキュメントを含む行を調べた後、JSON構文のテキストを解析することなくフィールドを抽出できます。ただし、行を検索するにはテーブルスキャンが必要です。つまり、クエリはすべての行を調べる必要があります。

同様に、電話帳で "Bill"という名前の人を検索している場合、電話帳のすべてのページを読む必要があります。

MySQL 5.7では、テーブルに仮想列を定義してから、仮想列にインデックスを作成できます。

ALTER TABLE t1
  ADD COLUMN series AS (JSON_EXTRACT(data, '$.series')),
  ADD INDEX (series);

次に、仮想列をクエリすると、インデックスが使用され、テーブルスキャンが回避されます。

SELECT * FROM t1
WHERE series IN ...

これはすばらしいことですが、JSONを使用する意味を欠いています。JSONを使用することの魅力的な部分は、ALTER TABLEを実行しなくても新しい属性を追加できることです。ただし、インデックスを使用してJSONフィールドを検索する場合は、とにかく追加の(仮想)列を定義する必要があります。

ただし、JSONドキュメントのすべてのフィールドに仮想列とインデックスを定義する必要はありません。検索またはソートしたいフィールドのみを定義する必要があります。次のように、選択リストで抽出する必要があるだけのJSONの他の属性がある可能性があります。

SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>

これはMySQLでJSONを使用するための最良の方法であると一般的に言っています。選択リストのみ。

他の句(JOIN、WHERE、GROUP BY、HAVING、ORDER BY)で列を参照する場合、JSONドキュメント内のフィールドではなく、従来の列を使用する方が効率的です。

2018年4月のPercona Liveカンファレンスで、MySQL WrongJSONを使用する方法という講演を行いました。秋にOracle Code Oneで講演を更新して繰り返します。

JSONには他にも問題があります。たとえば、私のテストでは、同じデータを格納する従来の列と比較して、JSONドキュメント用に2〜3倍のストレージスペースが必要でした。

MySQLは、主にMongoDBへの移行を阻止するために、新しいJSON機能を積極的に宣伝しています。しかし、MongoDBのようなドキュメント指向のデータストレージは、基本的にはデータを編成する非リレーショナルな方法です。リレーショナルとは異なります。私はどちらかが他より優れていると言っているわけではありません。それは、さまざまなタイプのクエリに適した、単に別のテクニックです。

JSONによってクエリがより効率的になる場合は、JSONの使用を選択する必要があります。

テクノロジーが新しいという理由だけで、またはファッションのために選択しないでください。


編集:MySQLの仮想列の実装は、WHERE句が仮想列の定義とまったく同じ式を使用する場合、インデックスを使用することになっています。つまり、仮想列が定義されているため、次仮想列のインデックスを使用する必要がありますAS (JSON_EXTRACT(data,"$.series"))

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

この機能をテストしたところ、式がJSON抽出関数の場合、何らかの理由で機能しないことがわかりました。JSON関数ではなく、他のタイプの式で機能します。


7
スライドへのリンクをたどる価値は十分あります
Paul Campbell

良い点は、2つのテクノロジーがどちらも優れているということです。つまり、どちらが私たちのニーズに合うかを決定し、何がセキュリティとパフォーマンスの面でより有利になるかを決定します。
Christopher Pelayo

1
問題の核心は、JSONの新しいキーごとに生成された列のインデックスを利用するために、ALTER TABLEが依然として必要であることです。指摘されてうれしいです。
user1454926

仮想列やインデックスを追加する必要がある場合のみ。JSONデータを「ブラックボックス」として扱い、JSON内のサブフィールドを検索またはソートするクエリを実行しない場合は、その必要はありません。そのためJOIN、JSON WHEREやその他の句での参照を避けることをお勧めします。選択リストのJSON列をフェッチするだけです。
ビルカーウィン

スライドへのリンクが壊れています、@ BillKarwin。
Lakesare

43

MySQL 5.7の次のコードは、JSONでセクシーな印象をもたらします。

MySQLでJSONデータ型を使用すると、テキストフィールドにJSON文字列を格納するよりも2つの利点があります。

データ検証。JSONドキュメントは自動的に検証され、無効なドキュメントはエラーになります。内部ストレージ形式の改善。JSONデータは、構造化された形式でデータへの迅速な読み取りアクセスを可能にする形式に変換されます。サーバーはサブオブジェクトまたはネストされた値をキーまたはインデックスで検索できるため、柔軟性とパフォーマンスが向上します。

...

NoSQLストア(ドキュメントDB、Key-Valueストア、グラフDB)の特殊なフレーバーは、特定のユースケースに適したオプションですが、このデータ型を追加すると、テクノロジースタックの複雑さを軽減できる場合があります。価格はMySQL(または互換性のある)データベースへのカップリングです。しかし、それは多くのユーザーにとって問題ではありません。

ドキュメントの検証に関する言語は重要な要素なので注意してください。2つのアプローチを比較するには、一連のテストを実行する必要があると思います。これらの2つは:

  1. JSONデータ型のMySQL
  2. Mysqlなし

ネットには、今のところmysql / json /パフォーマンスのトピックに関して、私が見ているものからスライドシェアは浅いですが。

おそらくあなたの投稿はそれのためのハブになることができます。あるいは、パフォーマンスは後から考えたものかもしれませんが、定かではありません。大量のテーブルを作成しないことに興奮しています。


7
1つの詐欺; JSONデータ型は、データ型TEXTおよびBLOBなどのMysqlメモリテーブルではサポートされていません。つまり、一時テーブルが必要な場合は、メモリではなくディスクベースのテーブルが作成されます。一時テーブルが使用されるいくつかのケースは、ここで概説されています: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media

1
@raizmediaディスクベースのテーブルがメモリ(ベースのテーブルだと思います)と比較して問題がある理由を詳しく説明してください。
lapin

@lapinおそらく速度制限によるものです。
リトルヘルパー

@LittleHelperでは、PCI 4x 40 Gb / s M.2スロットを使用し、40 Gb / s対応のドライブを挿入すれば回避できます。これはメモリと同じ速さで機能します。メモリをフォーマットするために使用されるドライブに特別なフォーマットを適用することもできます。
セルゲイロマノフ

@SergeyRomanov、[citation required]そのドライブとRAMのベンチマークを行いましたか?
Bill Karwin

11

私は最近この問題に遭遇し、以下の経験を要約します:

1、すべての質問を解決する方法はありません。2、JSONを適切に使用する必要があります。

1つのケース:

次の名前のテーブルがあります。CustomFieldそれは2つの列でなければなりません:namefieldsnameローカライズされた文字列です。コンテンツは次のようになります。

{
  "en":"this is English name",
  "zh":"this is Chinese name"
   ...(other languages)
}

そしてfields、このようにする必要があります:

[
  {
    "filed1":"value",
    "filed2":"value"
    ...
  },
  {
    "filed1":"value",
    "filed2":"value"
    ...
  }
  ...
]

ご覧のとおり、nameおよびの両方fieldsをJSONとして保存できます。

ただし、を使用しnameてこのテーブルを頻繁に検索する場合、どうすればよいですか?使用しJSON_CONTAINSJSON_EXTRACT...?明らかに、これをJSONとして保存することはお勧めできませんCustomFieldName。独立したテーブルに保存する必要があります。

上記のケースから、これらのアイデアを覚えておくべきだと思います:

  1. MYSQLがJSONをサポートする理由
  2. JSONを使用する理由 あなたのビジネスロジックはこれを必要としましたか?または他に何かありますか?
  3. 怠惰になるな

ありがとう


2
VIRTUAL列の使用に興味があるかもしれません。percona.com/blog/2016/03/07/...
ベル

10

私の経験から、少なくともMySql 5.7でのJSONの実装は、パフォーマンスが低いためあまり役に立ちません。まあ、それはデータの読み取りと検証にはそれほど悪くありません。ただし、JSONの変更は、PythonまたはPHPを使用した場合よりもMySqlを使用した場合の方が10〜20倍遅くなります。非常に単純なJSONを想像してみましょう。

{ "name": "value" }

それをそのようなものに変換する必要があるとしましょう:

{ "name": "value", "newName": "value" }

すべての行を選択して1つずつ更新するPythonまたはPHPで簡単なスクリプトを作成できます。巨大なトランザクションを1つ作成する必要がないため、他のアプリケーションがテーブルを並行して使用できます。もちろん、必要に応じて1つの巨大なトランザクションを作成することもできます。そのため、MySqlが「オールオアナッシング」を実行することが保証されますが、他のアプリケーションは、トランザクション実行中にデータベースを使用できない可能性があります。

4,000万行のテーブルがあり、Pythonスクリプトはそれを3〜4時間で更新します。

これでMySql JSONができたので、PythonやPHPはもう必要ありません。次のようにすることができます。

UPDATE `JsonTable` SET `JsonColumn` = JSON_SET(`JsonColumn`, "newName", JSON_EXTRACT(`JsonColumn`, "name"))

それはシンプルで優れています。ただし、その速度はPythonバージョンより10〜20倍遅く、単一トランザクションであるため、他のアプリケーションはテーブルデータを並行して変更できません。

したがって、4000万行のテーブルでJSONキーを複製するだけの場合は、30〜40時間はテーブルをまったく使用する必要がありません。それには意味がありません。

データの読み取りについては、私の経験から、JSON_EXTRACTin を介したJSONフィールドへの直接アクセスWHEREも非常に遅くなっています(インデックス付けされていない列を使用TEXTLIKEた場合よりもはるかに遅くなります)。仮想生成列ははるかに高速に実行されますが、事前にデータ構造がわかっている場合は、JSONは必要なく、代わりに従来の列を使用できます。JSONを本当に便利な場所で使用する場合、つまりデータ構造が不明であるか、頻繁に変更される場合(たとえば、カスタムプラグイン設定)、新しい列の可能性がある定期的な仮想列の作成は良いアイデアのようには見えません。

PythonとPHPはJSON検証を魅力的なものにするため、MySql側でJSON検証が必要なのかどうかは疑問です。XML、Microsoft Officeドキュメントを検証したり、スペルチェックを行ってみませんか?;)

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