SQLite3 не использует закрывающий индекс с выражением json_extract

8

Я пытаюсь создать индекс в SQLite3(3.18), используя json_extractвыражения. Моя цель состоит в том, чтобы выполнять запросы, которые требуют только индекса для получения результатов. Причина этого заключается в том, что json_extractэто дорогостоящая операция, которая может снизить производительность при работе с большими наборами данных и / или значениями. Я пришел к выводу, что мне нужен индекс покрытия, чтобы удовлетворить мои потребности.

Шаг 1 - Проверка теории с использованием нормальной структуры таблицы

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

Урожайность

SCAN TABLE Player USING COVERING INDEX Player_FirstName

Это именно то, что я ожидаю. Планировщик запросов выяснил, что Player_FirstNameиндекс является подходящим из-за ORDER BYпредложения, и поскольку WHEREоператор работает только со значением, которое также содержится в этом индексе, ему не нужно читать таблицу. Наконец, SELECTоператор включает только индексированные столбцы поэтому полученные в запросе, не задевает таблицу на всех .

Шаг 2 - Проверка теории с помощью выражения выдержки

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

Урожайность

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Это не то, что я ожидал. Планировщик запросов, похоже, выяснил, что ORDER BYпредложение включено JSON_EXTRACT(Data, '$.FirstName'), и, таким образом, выбрал соответствующий индекс. Но на этом мои рассуждения внезапно заканчиваются. Что здесь происходит? Я ожидал, что планировщик запросов выяснит, что это то же самое, что и предыдущий тест, и индекс будет использоваться в качестве покрывающего индекса. Но это не так.

Почему бы нет? И как можно изменить этот второй тест, чтобы он работал только с индексом?

Hozuki
источник

Ответы:

2

В документации сказано:

Планировщик запросов SQLite рассмотрит использование индекса для выражения, когда индексируемое выражение появляется в предложении WHERE или в предложении ORDER BY запроса.

Поэтому выражения в предложении SELECT не будут использовать индекс выражения.

Использование покрывающего индекса не является таким уж большим улучшением по сравнению с использованием обычного индекса для поиска / сортировки, так как использование обычного индекса было бы по сравнению с отсутствием индекса вообще, поэтому эта оптимизация (пока?) Не была реализована для индексов выражений.

CL.
источник
Использование выражений JSON_EXTRACT в выражении WHERE и / или ORDER BY эквивалентно, поскольку я просто создал псевдоним с полями SELECT. Переписывание запроса с использованием JSON_EXTRACT вместо псевдонима не дает другого результата.
Хозуки