SQLite3 tidak menggunakan indeks penutup dengan ekspresi json_extract

8

Saya mencoba membuat indeks di SQLite3(3.18) menggunakan json_extractekspresi. Tujuan saya adalah menjalankan kueri yang hanya memerlukan indeks untuk menghasilkan hasil. Alasannya adalah karena json_extractini merupakan operasi yang mahal yang akan menghambat kinerja saat beroperasi pada kumpulan data dan / atau nilai yang lebih besar. Saya menyimpulkan saya perlu indeks penutup yang sesuai dengan kebutuhan saya.

Langkah 1 - Menguji teori menggunakan struktur tabel 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

Hasil

SCAN TABLE Player USING COVERING INDEX Player_FirstName

Inilah yang saya harapkan. Perencana kueri memperkirakan bahwa Player_FirstNameindeks tersebut sesuai karena ORDER BYklausa, dan karena WHEREpernyataan itu hanya beroperasi pada nilai yang juga ada dalam indeks itu, ia tidak perlu membaca tabel. Akhirnya, SELECTpernyataan hanya menyertakan kolom yang diindeks karena itu menghasilkan permintaan yang tidak menyentuh tabel sama sekali .

Langkah 2 - Menguji teori dengan ekspresi ekstrak

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

Hasil

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Ini bukan yang saya harapkan. Perencana kueri tampaknya telah mengetahui bahwa ORDER BYklausa aktif JSON_EXTRACT(Data, '$.FirstName'), dan dengan demikian tampaknya telah memilih indeks yang sesuai. Tapi di situlah alasan saya berakhir dengan tiba-tiba. Apa yang terjadi disini? Saya berharap perencana kueri mengetahui bahwa ini sama dengan tes sebelumnya, dan indeks akan digunakan sebagai indeks penutup. Tapi ternyata tidak.

Kenapa tidak? Dan bagaimana tes kedua ini dapat dimodifikasi sehingga hanya berjalan terhadap indeks?

Hozuki
sumber

Jawaban:

2

The dokumentasi mengatakan:

Perencana kueri SQLite akan mempertimbangkan menggunakan indeks pada ekspresi ketika ekspresi yang diindeks muncul di klausa WHERE atau dalam klausa ORDER BY.

Jadi ekspresi dalam klausa SELECT tidak akan menggunakan indeks ekspresi.

Menggunakan indeks penutup tidak sebanyak perbaikan menggunakan indeks normal untuk mencari / menyortir seperti menggunakan indeks normal akan lebih dari tidak menggunakan indeks sama sekali, jadi optimasi ini belum (belum?) Diimplementasikan untuk indeks ekspresi.

CL.
sumber
Menggunakan ekspresi JSON_EXTRACT dalam pernyataan WHERE dan / atau ORDER BY adalah sama karena saya hanya membuat alias dengan bidang SELECT. Menulis ulang kueri untuk menggunakan JSON_EXTRACT alih-alih alias menghasilkan hasil yang tidak berbeda.
Hozuki