SQLite3 n'utilise pas d'index de couverture avec l'expression json_extract

8

J'essaie de créer un index en SQLite3(3.18) en utilisant des json_extractexpressions. Mon objectif est d'exécuter des requêtes qui ne nécessitent que l'index pour produire des résultats. La raison en est qu'il json_extracts'agit d'une opération coûteuse qui entraverait les performances lors de l'utilisation sur des ensembles de données et / ou des valeurs plus importants. J'ai conclu que j'avais besoin d'un indice de couverture adapté à mes besoins.

Étape 1 - Tester la théorie en utilisant une structure de table normale

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

Rendements

SCAN TABLE Player USING COVERING INDEX Player_FirstName

C'est exactement ce que j'attends. Le planificateur de requêtes a supposé que l' Player_FirstNameindex est approprié en raison de la ORDER BYclause, et puisque l' WHEREinstruction ne fonctionne que sur une valeur qui se trouve également dans cet index, il n'a pas besoin de lire la table. Enfin, l' SELECTinstruction inclut uniquement les colonnes indexées, ce qui entraîne une requête qui ne touche pas du tout à la table .

Étape 2 - Tester la théorie avec une expression d'extrait

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

Rendements

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Ce n'est pas ce à quoi je m'attendais. Le planificateur de requêtes semble avoir compris que la ORDER BYclause est JSON_EXTRACT(Data, '$.FirstName')activée et semble donc avoir sélectionné l'index approprié. Mais c'est là que mon raisonnement se termine brusquement. Qu'est-ce qui se passe ici? Je m'attendais à ce que le planificateur de requêtes découvre que c'est la même chose que le test précédent, et que l'index serait utilisé comme index de couverture. Mais ce n'est pas le cas.

Pourquoi pas? Et comment modifier ce deuxième test pour qu'il ne s'exécute que contre l'index?

Hozuki
la source

Réponses:

2

La documentation dit:

Le planificateur de requêtes SQLite envisagera d'utiliser un index sur une expression lorsque l'expression indexée apparaît dans la clause WHERE ou dans la clause ORDER BY d'une requête.

Les expressions de la clause SELECT n'utilisent donc pas l'index d'expression.

L'utilisation d'un index de couverture n'est pas autant une amélioration par rapport à l'utilisation d'un index normal pour la recherche / le tri que l'utilisation d'un index normal serait plus l'utilisation d'aucun index du tout, donc cette optimisation n'a pas (encore?) Été mise en œuvre pour les index d'expression.

CL.
la source
L'utilisation des expressions JSON_EXTRACT dans l'instruction WHERE et / ou ORDER BY est équivalente car j'ai simplement créé un alias avec les champs SELECT. La réécriture de la requête pour utiliser JSON_EXTRACT au lieu de l'alias ne donne aucun résultat différent.
Hozuki