【问题标题】:SQLite: Should LIKE 'searchstr%' use an index?SQLite:LIKE 'searchstr%' 应该使用索引吗?
【发布时间】:2012-01-24 22:49:13
【问题描述】:

我有一个包含多个字段的数据库

word_id — INTEGER PRIMARY_KEY
word — TEXT
...

..和 ~150k 行。

由于这是一本字典,我正在使用 LIKE 搜索带有掩码 'search_string%' 的单词。 它过去工作得很好,需要 15 毫秒才能找到匹配的行。该表具有字段'word' 的索引。 最近我修改了表(该表的某些字段超出了范围)并且发生了一些事情 - 执行查询需要 400 毫秒,所以我理解它现在无法使用索引。 使用 = 而不是 like 的直接查询显示 10 毫秒的结果。 有人知道这里发生了什么吗?

【问题讨论】:

  • 我想是的,你可能想看看b-tree,因为b-tree在范围查询和比较方面很有效。
  • 嗯,索引不是假设b-tree的创建吗?你的意思是,我应该自己创建一个 b-tree?
  • % 总是只在搜索词的末尾,而不是开头吗?
  • 也许尝试删除并重新创建索引?
  • 您应该尝试使用EXPLAIN QUERY PLAN 来查看您的查询发生了什么。

标签: sql sqlite cocoa sql-like query-performance


【解决方案1】:

在这种情况下不能安全地使用索引。一个天真的实现会改变这个:

... WHERE word LIKE 'search_string%'

进入

... WHERE word >= 'search_string' AND word < 'search_strinh'

通过递增搜索字符串的最后一个字符。大于和小于运算符可以使用索引,而 LIKE 不能。

很遗憾,这在一般情况下不起作用。 LIKE 运算符不区分大小写,这意味着 'a' LIKE 'A' 为真。上述转换会破坏任何带有大写字母的搜索字符串。

然而,在某些情况下,您知道区分大小写与特定列无关,并且上述转换是安全的。在这种情况下,您有两种选择。

  1. 在涵盖此特定字段的索引上使用 NOCASE 整理序列。
  2. 通过运行 PRAGMA case_sensitive_like = ON; 在程序范围内更改 LIKE 运算符的行为

这些行为中的任何一个都将使 SQLite 透明地为您进行上述转换;你只需像往常一样继续使用LIKE,SQLite 将重写底层查询以使用索引。

您可以在SQLite Query Optimizer Overview page 上阅读有关“LIKE 优化”的更多信息。

【讨论】:

  • 该死!在上面的线程中,我提到我上次创建索引(有效)时一直在使用一些参数。所以,那是COLLATE NOCASE。我花了大约6个小时无济于事。不错的链接,我也读过它,但它似乎只是从我的注意力中滑落。谢谢你,荷马!天知道你为我节省了多少时间。
  • 我认为你的意思是PRAGMA case_sensitive_like = ON; 就像你说的,LIKE 默认情况下不区分大小写。从您链接到的文章中:“如果使用内置的 BINARY 排序序列对运算符左侧命名的列进行索引并且打开了 case_sensitive_like,则可能会发生 LIKE 优化。”
  • 啊,真的。我会修复它。谢谢!
  • COLLATE NOCASE 使用索引的语法是CREATE INDEX index_name ON table_name (column_name COLLATE NOCASE);,如果有人感兴趣的话。
猜你喜欢
  • 1970-01-01
  • 2013-01-03
  • 2011-12-22
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2017-03-19
  • 2012-02-14
  • 2017-04-03
相关资源
最近更新 更多