可以优化LIKE语句以不进行全表扫描吗?

时间:2013-12-06 12:01:32

标签: sqlite query-optimization sql-like

我希望通过树路径从表中获取子树。

path列存储字符串,如:

foo/
foo/bar/
foo/bar/baz/

如果我尝试选择以某条路径开头的所有记录:

EXPLAIN QUERY PLAN SELECT * FROM f WHERE path LIKE "foo/%"

它告诉我即使path列被编入索引,也会扫描该表:(

有什么方法可以让LIKE使用索引而不扫描表吗?

我找到了一种方法来实现我想要的闭包表,但是它更难维护,写入速度非常慢......

2 个答案:

答案 0 :(得分:3)

LIKE具有严格的要求,可以使用索引(ref)进行优化。

如果您可以稍微放松一下您的要求,您可以使用词典排序来获取索引查找,例如

SELECT * FROM f WHERE PATH >= 'foo/' AND PATH < 'foo0'

其中0/之后的词典下一个字符。

如果满足优化要求,这与优化程序对LIKE的优化基本相同。

答案 1 :(得分:3)

为了能够在SQLite中使用LIKE索引,

  1. 表格列必须包含TEXT affinity,即具有TEXT或VARCHAR类型或类似内容;和
  2. 索引必须声明为COLLATE NOCASE(直接或因为该列已声明为COLLATE NOCASE):

    > CREATE TABLE f(path TEXT);
    > CREATE INDEX fi ON f(path COLLATE NOCASE);
    > EXPLAIN QUERY PLAN SELECT * FROM f WHERE path LIKE 'foo/%';
    0|0|0|SEARCH TABLE f USING COVERING INDEX fi (path>? AND path<?)
    
  3. 可以使用case_sensitive_like PRAGMA删除第二个限制,但这会改变LIKE的行为。 或者,可以使用LIKE 'foo/%'替换GLOB 'foo/*'来使用区分大小写的比较。