SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...
このような式または関数内で列を使用すると、クエリを最適化するためにインデックスを使用するクエリの可能性が損なわれます。上記のクエリは、テーブルスキャンを強制的に実行します。
「効率的なアクセス」に関する主張は誤解を招く恐れがあります。これは、クエリがJSONドキュメントを含む行を調べた後、JSON構文のテキストを解析しなくてもフィールドを抽出できることを意味します。ただし、行を検索するにはテーブルスキャンが必要です。つまり、クエリはすべての行を調べる必要があります。
類推すると、電話帳で「ビル」という名前の人を検索する場合、名前が強調表示されていても、電話帳のすべてのページを読む必要があります。これにより、名前を簡単に見つけることができます。
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を使用することの魅力的な部分は、ALTERTABLEを実行しなくても新しい属性を追加できることです。ただし、インデックスを使用して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ドキュメント内のフィールドではなく、従来の列を使用する方が効率的です。
MySQLでJSONを使用する方法という講演を行いました間違った 2018年4月のPerconaLiveカンファレンスで。秋にOracleCodeOneでの講演を更新して繰り返します。
JSONには他にも問題があります。たとえば、私のテストでは、同じデータを保存する従来の列と比較して、JSONドキュメントに2〜3倍のストレージスペースが必要でした。
MySQLは、主にMongoDBへの移行を思いとどまらせるために、新しいJSON機能を積極的に推進しています。しかし、MongoDBのようなドキュメント指向のデータストレージは、基本的にデータを整理するための非リレーショナルな方法です。リレーショナルとは異なります。どちらかがもう一方より優れていると言っているのではありません。これは、さまざまな種類のクエリに適した、単なる別の手法です。
JSONを使用するとクエリがより効率的になる場合は、JSONを使用することを選択する必要があります。
新しいという理由だけで、またはファッションのためにテクノロジーを選択しないでください。
編集:WHERE句が仮想列の定義とまったく同じ式を使用している場合、MySQLの仮想列の実装はインデックスを使用することになっています。つまり、次の 仮想列はAS (JSON_EXTRACT(data,"$.series"))
として定義されているため、仮想列のインデックスを使用します
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...
この機能をテストして、式がJSON抽出関数の場合、何らかの理由で機能しないことがわかった場合を除きます。 JSON関数ではなく、他のタイプの式で機能します。更新:これは、最終的にMySQL5.7.33で機能すると報告されています。