SQLite3 không sử dụng chỉ mục che với biểu thức json_extract


8

Tôi đang cố gắng tạo một chỉ mục trong SQLite3(3.18) bằng các json_extractbiểu thức. Mục đích của tôi là thực hiện các truy vấn chỉ yêu cầu chỉ mục để mang lại kết quả. Lý do cho điều này là json_extractmột hoạt động đắt tiền sẽ cản trở hiệu suất khi hoạt động trên các tập dữ liệu và / hoặc giá trị lớn hơn. Tôi kết luận tôi cần một chỉ số bao phủ phù hợp với nhu cầu của tôi.

Bước 1 - Kiểm tra lý thuyết bằng cấu trúc bảng bình thường

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

Sản lượng

SCAN TABLE Player USING COVERING INDEX Player_FirstName

Đây chính xác là những gì tôi mong đợi. Trình hoạch định truy vấn đã chỉ ra rằng Player_FirstNamechỉ mục phù hợp do ORDER BYmệnh đề và vì WHEREcâu lệnh chỉ hoạt động trên một giá trị cũng nằm trong chỉ mục đó, nên không cần phải đọc bảng. Cuối cùng, SELECTtuyên bố chỉ bao gồm các cột được đánh chỉ mục do đó dẫn đến một truy vấn mà không chạm vào bàn ở tất cả .

Bước 2 - Kiểm tra lý thuyết với biểu thức trích xuất

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

Sản lượng

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

Đây không phải là những gì tôi mong đợi. Trình hoạch định truy vấn dường như đã tìm ra rằng ORDER BYmệnh đề này được bật JSON_EXTRACT(Data, '$.FirstName')và do đó dường như đã chọn chỉ mục thích hợp. Nhưng đó là nơi lý luận của tôi kết thúc đột ngột. Chuyện gì đang xảy ra ở đây? Tôi đã dự kiến ​​trình hoạch định truy vấn sẽ chỉ ra rằng đây giống như thử nghiệm trước đó và chỉ mục sẽ được sử dụng làm chỉ mục bao trùm. Nhưng nó không.

Tại sao không? Và làm thế nào thử nghiệm thứ hai này có thể được sửa đổi để nó chỉ chạy với chỉ số?

Câu trả lời:


2

Các tài liệu nói:

Trình lập kế hoạch truy vấn SQLite sẽ xem xét sử dụng một chỉ mục trên một biểu thức khi biểu thức được lập chỉ mục xuất hiện trong mệnh đề WHERE hoặc trong mệnh đề ORDER BY của một truy vấn.

Vì vậy, các biểu thức trong mệnh đề SELECT sẽ không sử dụng chỉ mục biểu thức.

Sử dụng một chỉ mục che phủ không phải là một sự cải thiện so với việc sử dụng một chỉ mục bình thường để tìm kiếm / sắp xếp như sử dụng một chỉ mục bình thường sẽ không sử dụng chỉ mục nào cả, vì vậy việc tối ưu hóa này chưa được thực hiện cho các chỉ mục biểu thức.


Sử dụng các biểu thức JSON_EXTRACT trong câu lệnh WHERE và / hoặc ORDER BY là tương đương vì tôi chỉ tạo một bí danh với các trường SELECT. Viết lại truy vấn để sử dụng JSON_EXTRACT thay vì bí danh không mang lại kết quả khác.
Hozuki
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.