【发布时间】:2020-02-29 05:30:31
【问题描述】:
在 SQLite 中,文本列上的索引能否加快基于前缀的 LIKE 列查询?
例如,如果我有一个名为 path 的 TEXT 列并且我运行类似于 WHERE path LIKE '/path/to/some/dir/%' 的查询,该查询是否能够从该 path 列上的索引中受益?
【问题讨论】:
标签: sqlite indexing text sql-like
在 SQLite 中,文本列上的索引能否加快基于前缀的 LIKE 列查询?
例如,如果我有一个名为 path 的 TEXT 列并且我运行类似于 WHERE path LIKE '/path/to/some/dir/%' 的查询,该查询是否能够从该 path 列上的索引中受益?
【问题讨论】:
标签: sqlite indexing text sql-like
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
【讨论】:
LIKE 的所有内容都不匹配。)
是的,它会,具有正确的索引。如果使用默认不区分大小写的LIKE 模式,索引也需要不区分大小写。还有其他限制,请参阅LIKE optimization documentation 了解详细信息(很长且难以总结)。
例子:
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,因为它已经被暗示了。
【讨论】: