SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...
Brug af en kolonne inde i et udtryk eller en funktion som denne ødelægger enhver chance for, at forespørgslen bruger et indeks til at hjælpe med at optimere forespørgslen. Forespørgslen vist ovenfor er tvunget til at foretage en tabelscanning.
Påstanden om "effektiv adgang" er vildledende. Det betyder, at efter at forespørgslen har undersøgt en række med et JSON-dokument, kan den udtrække et felt uden at skulle parse teksten i JSON-syntaksen. Men det kræver stadig en tabelscanning at søge efter rækker. Med andre ord skal forespørgslen undersøge hver række.
Analogt, hvis jeg søger i en telefonbog efter personer med fornavnet "Bill", skal jeg stadig læse hver side i telefonbogen, selvom fornavnene er fremhævet for at gøre det lidt hurtigere at få øje på dem.
MySQL 5.7 giver dig mulighed for at definere en virtuel kolonne i tabellen og derefter oprette et indeks på den virtuelle kolonne.
ALTER TABLE t1
ADD COLUMN series AS (JSON_EXTRACT(data, '$.series')),
ADD INDEX (series);
Hvis du derefter forespørger på den virtuelle kolonne, kan den bruge indekset og undgå tabelscanningen.
SELECT * FROM t1
WHERE series IN ...
Det er rart, men det går lidt glip af pointen med at bruge JSON. Den attraktive del af at bruge JSON er, at det giver dig mulighed for at tilføje nye attributter uden at skulle gøre ALTER TABLE. Men det viser sig, at du alligevel skal definere en ekstra (virtuel) kolonne, hvis du vil søge i JSON-felter ved hjælp af et indeks.
Men du behøver ikke at definere virtuelle kolonner og indekser for hver felt i JSON-dokumentet – kun dem, du vil søge eller sortere på. Der kan være andre attributter i JSON, som du kun behøver at udtrække i valglisten som følgende:
SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>
Jeg vil generelt sige, at dette er den bedste måde at bruge JSON i MySQL. Kun på udvalgslisten.
Når du refererer til kolonner i andre klausuler (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), er det mere effektivt at bruge konventionelle kolonner, ikke felter i JSON-dokumenter.
Jeg præsenterede en tale kaldet Sådan bruges JSON i MySQL Forkert ved Percona Live-konferencen i april 2018. Jeg vil opdatere og gentage foredraget på Oracle Code One til efteråret.
Der er andre problemer med JSON. For eksempel krævede det i mine test 2-3 gange så meget lagerplads til JSON-dokumenter sammenlignet med konventionelle kolonner, der lagrer de samme data.
MySQL promoverer deres nye JSON-funktioner aggressivt, hovedsageligt for at afholde folk fra at migrere til MongoDB. Men dokumentorienteret datalagring som MongoDB er grundlæggende en ikke-relationel måde at organisere data på. Det er anderledes end relationelt. Jeg siger ikke, at den ene er bedre end den anden, det er bare en anden teknik, egnet til forskellige typer forespørgsler.
Du bør vælge at bruge JSON, når JSON gør dine forespørgsler mere effektive.
Vælg ikke en teknologi, bare fordi den er ny eller for modens skyld.
Rediger:Den virtuelle kolonneimplementering i MySQL formodes at bruge indekset, hvis din WHERE-klausul bruger nøjagtigt det samme udtryk som definitionen af den virtuelle kolonne. Det vil sige, at følgende bør brug indekset på den virtuelle kolonne, da den virtuelle kolonne er defineret AS (JSON_EXTRACT(data,"$.series"))
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...
Bortset fra, at jeg ved at teste denne funktion har fundet ud af, at den IKKE virker af en eller anden grund, hvis udtrykket er en JSON-ekstraktionsfunktion. Det virker til andre typer udtryk, bare ikke JSON-funktioner. OPDATERING:efter sigende virker dette endelig i MySQL 5.7.33.