web-dev-qa-db-ja.com

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

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

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

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

パフォーマンス-JSON列内の値にインデックスを作成して、クエリのパフォーマンスを改善します。これは、仮想列の「機能インデックス」で実現できます。

Convenience-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データ型の長所と短所。

91
Imran
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ドキュメントのeveryフィールドに仮想列とインデックスを定義する必要はありません。検索またはソートしたいものだけを定義します。 JSONには、次のように選択リストで抽出するだけでよい他の属性があります。

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

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

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

2018年4月のPercona Liveカンファレンスで、 How to Use JSON in MySQL Wrong と呼ばれる講演を行いました。秋にOracle Code Oneで講演を更新し、繰り返します。

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

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

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

技術が新しいからという理由だけで、またはファッションのために技術を選択しないでください。

28
Bill Karwin

MySQL 5.7の次のコードは、JSONでセクシーを取り戻します

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

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

...

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

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

  1. JSONデータ型を使用したMySQL
  2. Mysqlなし

私が見ているものからmysql/json/performanceのトピックについては、ネットには今のところ浅いスライドシェアがあります。

おそらくあなたの投稿がそのハブになる可能性があります。あるいは、パフォーマンスはよくわからないので後から考えて、テーブルを大量に作成しないことに興奮しています。

42
Drew

最近この問題に遭遇し、次の経験を要約します。

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

1つのケース:

CustomFieldという名前のテーブルがあり、namefieldsという2つの列が必要です。 nameはローカライズされた文字列で、コンテンツは次のようになります。

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

fieldsは次のようになります。

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

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

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

上記のケースから、これらのアイデアを念頭に置いておく必要があると思います。

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

ありがとう

10
Bruce

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

{ "name": "value" }

それをそのようなものに変換しなければならないとしましょう:

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

PythonまたはPHPを使用してすべての行を選択し、それらを1つずつ更新する単純なスクリプトを作成できます。そのために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倍遅く、単一のトランザクションであるため、他のアプリケーションはテーブルデータを並行して変更できません。

そのため、4,000万行のテーブルでJSONキーを複製する場合、30〜40時間はテーブルをまったく使用しないでください。意味がありません。

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

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

6
Vitalii