В sqlite, может ли индекс по текстовому столбцу ускорить запросы LIKE на основе префикса к столбцу? - PullRequest
0 голосов
/ 03 ноября 2019

Например, если у меня есть столбец TEXT с именем «path», и я запускаю запрос, аналогичный «WHERE path LIKE» / path / to / some / dir /% '», сможет ли этот запрос извлечь выгоду изиндекс для этого столбца "путь"?

Ответы [ 2 ]

1 голос
/ 04 ноября 2019

LIKE не получит выгоды от индекса (с параметром по умолчанию), но вы можете переписать свой запрос, используя GLOB или BETWEEN.

РЕШЕНИЕ 1

С регулярным индексом:

подобно => не оптимизировано

sqlite> explain query plan select * from pathdta where path like '/path/to/some/dir/a%' ;
0|0|0|SCAN TABLE pathdta

GLOB => оптимизировано

sqlite> explain query plan select * from pathdta where path GLOB '/path/to/some/dir/a*' ;
0|0|0|SEARCH TABLE pathdta USING COVERING INDEX ix_pathdta_dta (path>? AND path<?)

больше => оптимизировано

sqlite> explain query plan  select * from pathdta where path >= '/path/to/some/dir/a' ;
0|0|0|SEARCH TABLE pathdta USING COVERING INDEX ix_pathdta_dta (path>?)

равенство => оптимизировано

sqlite> explain query plan  select * from pathdta where path = '/path/to/some/dir/a' ;
0|0|0|SEARCH TABLE pathdta USING COVERING INDEX ix_pathdta_dta (path=?)

между => оптимизировано

sqlite> explain query plan  select * from pathdta
   ...>    where path between '/path/to/some/dir/a' and '/path/to/some/dir/b' ;
0|0|0|SEARCH TABLE pathdta USING COVERING INDEX ix_pathdta_dta (path>? AND path<?)

РЕШЕНИЕ 2

используйте индекс collate nocase.

как => оптимизировано

sqlite> explain query plan select * from pathdta where path like '/path/to/some/dir/a%' ;
0|0|0|SEARCH TABLE pathdta USING COVERING INDEX ix_pathdta_dta (path>? AND path<?)

glob => не оптимизировано

sqlite> explain query plan select * from pathdta where path GLOB '/path/to/some/dir/a*' ;
0|0|0|SCAN TABLE pathdta

больше => не оптимизировано

sqlite> explain query plan  select * from pathdta where path >= '/path/to/some/dir/a' ;
0|0|0|SCAN TABLE pathdta

равенство => не оптимизировано

sqlite> explain query plan  select * from pathdta where path = '/path/to/some/dir/a' ;
0|0|0|SCAN TABLE pathdta

между => не оптимизировано

sqlite> explain query plan  select * from pathdta
   ...>    where path between '/path/to/some/dir/a' and '/path/to/some/dir/b' ;
0|0|0|SCAN TABLE pathdta
0 голосов
/ 04 ноября 2019

Да, будет, с правильным индексом. Если используется режим LIKE без учета регистра по умолчанию, индекс также должен быть без учета регистра. Есть и другие ограничения, см. LIKE документация по оптимизации для получения полной информации (это довольно долго и сложно обобщить).

Пример:

sqlite> CREATE TABLE paths(id INTEGER PRIMARY KEY, path TEXT);
sqlite> CREATE INDEX paths_idx_path ON paths(path); -- case sensitive index
sqlite> EXPLAIN QUERY PLAN SELECT * FROM paths WHERE path LIKE 'foo%';
QUERY PLAN
`--SCAN TABLE paths
sqlite> DROP INDEX paths_idx_path;
sqlite> CREATE INDEX paths_idx_path ON paths(path COLLATE NOCASE); -- case insensitive index
sqlite> EXPLAIN QUERY PLAN SELECT * FROM paths WHERE path LIKE 'foo%';
QUERY PLAN
`--SEARCH TABLE paths USING COVERING INDEX paths_idx_path (path>? AND path<?)

КакВы можете видеть, что с учетом регистра без учета регистра запрос переписывается для поиска строк в определенном диапазоне, а не для сканирования всех строк в таблице.

Можно также указать, что все сравнениястолбец не чувствителен к регистру в определении таблицы:

CREATE TABLE paths(id INTEGER PRIMARY KEY, path TEXT COLLATE NOCASE);

, а затем для индекса не требуется COLLATE, поскольку он уже подразумевается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...