SQLite3 não usando índice de cobertura com expressão json_extract

8

Estou tentando criar um índice em SQLite3(3.18) usando json_extractexpressões. Meu objetivo é executar consultas que exigem apenas que o índice produza resultados. A razão para isso é que json_extracté uma operação cara que prejudicaria o desempenho ao operar com conjuntos de dados e / ou valores maiores. Concluí que preciso de um índice de cobertura para atender às minhas necessidades.

Etapa 1 - Testando a teoria usando uma estrutura de tabela normal

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

Rendimentos

SCAN TABLE Player USING COVERING INDEX Player_FirstName

É exatamente o que eu espero. O planejador de consultas concluiu que o Player_FirstNameíndice é apropriado devido à ORDER BYcláusula e, como a WHEREinstrução opera apenas em um valor que também está nesse índice, ela não precisa ler a tabela. Finalmente, a SELECTdeclaração inclui apenas as colunas indexadas, portanto, resultando em uma consulta que não toca a mesa em tudo .

Etapa 2 - Testando a teoria com uma expressão de extrato

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

Rendimentos

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Isso é não o que eu esperava. O planejador de consultas parece ter descoberto que a ORDER BYcláusula está JSON_EXTRACT(Data, '$.FirstName')ativada e, portanto, parece ter selecionado o índice apropriado. Mas é aí que meu raciocínio termina abruptamente. O que está acontecendo aqui? Eu esperava que o planejador de consultas descobrisse que isso é igual ao teste anterior e o índice seria usado como um índice de cobertura. Mas isso não acontece.

Por que não? E como esse segundo teste pode ser modificado para que seja executado apenas no índice?

Hozuki
fonte

Respostas:

2

A documentação diz:

O planejador de consultas SQLite considerará o uso de um índice em uma expressão quando a expressão indexada aparecer na cláusula WHERE ou na cláusula ORDER BY de uma consulta.

Portanto, as expressões na cláusula SELECT não usarão o índice de expressão.

O uso de um índice de cobertura não é tanto uma melhoria em relação ao uso de um índice normal para pesquisa / classificação, como o uso de um índice normal acabaria sem o uso de nenhum índice, portanto essa otimização ainda não foi implementada para índices de expressão.

CL.
fonte
O uso das expressões JSON_EXTRACT na instrução WHERE e / ou ORDER BY é equivalente, pois eu apenas fiz um alias com os campos SELECT. Reescrever a consulta para usar JSON_EXTRACT em vez do alias não produz resultados diferentes.
Hozuki