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 е, че ви позволява да добавяте нови атрибути, без да се налага да правите ALTER TABLE. Но се оказва, че така или иначе трябва да дефинирате допълнителна (виртуална) колона, ако искате да търсите в JSON полета с помощта на индекс.
Но не е нужно да дефинирате виртуални колони и индекси за всеки поле в документа JSON – само тези, които искате да търсите или сортирате. Може да има други атрибути в JSON, които трябва само да извлечете в списъка за избор, като следното:
SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>
Като цяло бих казал, че това е най-добрият начин за използване на JSON в MySQL. Само в списъка за избор.
Когато препращате към колони в други клаузи (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), по-ефективно е да използвате конвенционални колони, а не полета в JSON документи.
Представих беседа, наречена Как да използвам JSON в MySQL Грешно на конференцията на Percona Live през април 2018 г. Ще актуализирам и ще повторя разговора в Oracle Code One през есента.
Има и други проблеми с JSON. Например в моите тестове изискваше 2-3 пъти повече място за съхранение за JSON документи в сравнение с конвенционалните колони, съхраняващи същите данни.
MySQL популяризира агресивно новите си възможности за JSON, до голяма степен за да разубеди хората да не мигрират към MongoDB. Но документно ориентираното съхранение на данни като MongoDB е основно нерелационен начин за организиране на данни. Различно е от релационния. Не казвам, че едното е по-добро от другото, просто е различна техника, подходяща за различни видове заявки.
Трябва да изберете да използвате JSON, когато JSON прави заявките ви по-ефективни.
Не избирайте технология само защото е нова или заради модата.
Редактиране:Реализацията на виртуална колона в MySQL трябва да използва индекса, ако вашата клауза WHERE използва точно същия израз като дефиницията на виртуалната колона. Тоест, следното трябва използвайте индекса на виртуалната колона, тъй като виртуалната колона е дефинирана AS (JSON_EXTRACT(data,"$.series"))
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...
Освен че открих чрез тестване на тази функция, че тя НЕ работи по някаква причина, ако изразът е функция за извличане на JSON. Работи за други видове изрази, но не и за JSON функции. АКТУАЛИЗАЦИЯ:според съобщенията това най-накрая работи в MySQL 5.7.33.