SQLite3 non utilizza l'indice di copertura con l'espressione json_extract


8

Sto tentando di creare un indice in SQLite3(3.18) usando le json_extractespressioni. Il mio obiettivo è quello di eseguire query che richiedono solo l'indice per produrre risultati. La ragione di ciò è che json_extractè un'operazione costosa che ostacolerebbe le prestazioni quando si opera su set di dati e / o valori più grandi. Ho concluso che ho bisogno di un indice di copertura per soddisfare le mie esigenze.

Passaggio 1: test della teoria utilizzando una normale struttura della tabella

CREATE TABLE Player (
    Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    FirstName TEXT NOT NULL,
    MiddleName TEXT,
    LastName TEXT NOT NULL
);

CREATE INDEX Player_FirstName ON Player (
    FirstName ASC,
    LastName ASC
);

EXPLAIN QUERY PLAN SELECT
    FirstName, LastName
FROM
    Player
WHERE
    LENGTH(LastName) > 10
ORDER BY
    FirstName
LIMIT
    10
OFFSET
    0

I rendimenti

SCAN TABLE Player USING COVERING INDEX Player_FirstName

Questo è esattamente quello che mi aspetto. Il pianificatore di query ha calcolato che l' Player_FirstNameindice è appropriato a causa della ORDER BYclausola e poiché l' WHEREistruzione opera solo su un valore che si trova anche in quell'indice, non è necessario leggere la tabella. Infine, l' SELECTistruzione include solo le colonne indicizzate ne consegue una query che non tocca il tavolo affatto .

Passaggio 2: test della teoria con un'espressione extract

CREATE TABLE PlayerJ (
    Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    Data TEXT NOT NULL
);

CREATE INDEX PlayerJ_FirstName ON PlayerJ (
    JSON_EXTRACT(Data, '$.FirstName') ASC,
    JSON_EXTRACT(Data, '$.LastName') ASC
);

EXPLAIN QUERY PLAN SELECT
    JSON_EXTRACT(Data, '$.FirstName') AS FirstName,
    JSON_EXTRACT(Data, '$.LastName') AS LastName
FROM
    PlayerJ
WHERE
    LENGTH(LastName) > 10
ORDER BY
    FirstName
LIMIT
    10
OFFSET
    0

I rendimenti

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Questo non è quello che mi aspettavo. Il pianificatore di query sembra aver capito che la ORDER BYclausola è attiva JSON_EXTRACT(Data, '$.FirstName')e quindi sembra aver selezionato l'indice appropriato. Ma è qui che il mio ragionamento si interrompe bruscamente. Cosa sta succedendo qui? Mi sarei aspettato che il pianificatore di query potesse capire che era lo stesso del test precedente e che l'indice sarebbe stato usato come indice di copertura. Ma non lo fa.

Perchè no? E come può essere modificato questo secondo test in modo che venga eseguito solo sull'indice?

Risposte:


2

La documentazione dice:

Il pianificatore di query SQLite prenderà in considerazione l'utilizzo di un indice su un'espressione quando l'espressione indicizzata appare nella clausola WHERE o nella clausola ORDER BY di una query.

Pertanto, le espressioni nella clausola SELECT non utilizzeranno l'indice delle espressioni.

L'uso di un indice di copertura non è tanto un miglioramento rispetto all'utilizzo di un indice normale per la ricerca / l'ordinamento rispetto all'utilizzo di un indice normale rispetto all'utilizzo di nessun indice, quindi questa ottimizzazione non è stata (ancora?) Implementata per gli indici di espressione.


L'uso delle espressioni JSON_EXTRACT nelle istruzioni WHERE e / o ORDER BY è equivalente poiché ho semplicemente creato un alias con i campi SELECT. La riscrittura della query per utilizzare JSON_EXTRACT invece dell'alias non produce risultati diversi.
Hozuki,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.