SQLite3 no utiliza el índice de cobertura con la expresión json_extract


8

Estoy intentando crear un índice en SQLite3(3.18) usando json_extractexpresiones. Mi objetivo es ejecutar consultas que solo requieren que el índice produzca resultados. La razón de esto es que json_extractes una operación costosa que obstaculizaría el rendimiento cuando se opera en conjuntos de datos y / o valores más grandes. Llegué a la conclusión de que necesito un índice de cobertura para satisfacer mis necesidades.

Paso 1: prueba de la teoría utilizando una estructura de tabla 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

Rendimientos

SCAN TABLE Player USING COVERING INDEX Player_FirstName

Esto es exactamente lo que espero. El planificador de consultas calculó que el Player_FirstNameíndice es apropiado debido a la ORDER BYcláusula, y dado que la WHEREdeclaración opera solo en un valor que también está en ese índice, no necesita leer la tabla. Finalmente, la SELECTdeclaración incluye solo las columnas indexadas, lo que resulta en una consulta que no toca la tabla en absoluto .

Paso 2: prueba de la teoría con una expresión de extracto

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

Rendimientos

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Esto no es lo que esperaba. El planificador de consultas parece haber descubierto que la ORDER BYcláusula está JSON_EXTRACT(Data, '$.FirstName')activada y, por lo tanto, parece haber seleccionado el índice apropiado. Pero ahí es donde mi razonamiento termina abruptamente. ¿Que esta pasando aqui? Hubiera esperado que el planificador de consultas descubriera que esto es lo mismo que la prueba anterior, y el índice se usaría como índice de cobertura. Pero no lo hace.

Por qué no? ¿Y cómo se puede modificar esta segunda prueba para que solo se ejecute contra el índice?

Respuestas:


2

La documentación dice:

El planificador de consultas SQLite considerará usar un índice en una expresión cuando la expresión indexada aparezca en la cláusula WHERE o en la cláusula ORDER BY de una consulta.

Por lo tanto, las expresiones en la cláusula SELECT no usarán el índice de expresión.

El uso de un índice de cobertura no es tanto una mejora con respecto al uso de un índice normal para buscar / ordenar como el uso de un índice normal sería no usar ningún índice en absoluto, por lo que esta optimización no se ha implementado (¿todavía?) Para los índices de expresión.


Usar las expresiones JSON_EXTRACT en la instrucción WHERE y / o ORDER BY es equivalente, ya que simplemente hice un alias con los campos SELECT. Reescribir la consulta para usar JSON_EXTRACT en lugar del alias no produce un resultado diferente.
Hozuki
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.