【问题标题】:Can an index on a text column speed up prefix based LIKE queries?文本列上的索引可以加快基于前缀的 LIKE 查询吗?
【发布时间】:2020-02-29 05:30:31
【问题描述】:

在 SQLite 中,文本列上的索引能否加快基于前缀的 LIKE 列查询?

例如,如果我有一个名为 pathTEXT 列并且我运行类似于 WHERE path LIKE '/path/to/some/dir/%' 的查询,该查询是否能够从该 path 列上的索引中受益?

【问题讨论】:

标签: sqlite indexing text sql-like


【解决方案1】:

LIKE 不会从索引中受益(使用默认选项),但您可以使用 GLOBBETWEEN 重写查询。

解决方案 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

【讨论】:

  • Sqlite 在某些情况下会为你重写。请参阅我对原始问题的评论。
  • @Shawn 在我的测试中没有重写,请看我的 sqlfiddle
  • 您的测试不满足优化所需的约束条件。 (另外,您的手动版本与原始 LIKE 的所有内容都不匹配。)
【解决方案2】:

是的,它会,具有正确的索引。如果使用默认不区分大小写的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,因为它已经被暗示了。

【讨论】:

    猜你喜欢
    • 2021-07-22
    • 1970-01-01
    • 2016-06-23
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 2019-05-18
    • 2013-08-28
    • 1970-01-01
    相关资源
    最近更新 更多