【问题标题】:Can the LIKE statement be optimized to not do full table scans?LIKE 语句可以优化为不进行全表扫描吗?
【发布时间】:2013-12-23 18:34:42
【问题描述】:

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

path 列存储如下字符串:

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

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

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

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

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

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

【问题讨论】:

    标签: sqlite query-optimization sql-like


    【解决方案1】:

    LIKE 对使用索引 (ref) 进行优化有严格的要求。

    如果您可以稍微放宽您的要求,您可以使用字典顺序来获取索引查找,例如

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

    其中0/ 之后按字典顺序排列的下一个字符。

    如果满足优化要求,这与优化器对LIKEs 所做的优化基本相同。

    【讨论】:

    • 我正在阅读同一页,但得出了不同的结论。在第 4 章中,它指出它可以在非常严格的规则下进行优化。
    • 感谢这个使用搜索 :) 查询看起来有点奇怪
    【解决方案2】:

    为了能够在 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<?)
      

    可以使用case_sensitive_like PRAGMA 删除第二个限制,但这会改变 LIKE 的行为。 或者,可以使用区分大小写的比较,将LIKE 'foo/%' 替换为GLOB 'foo/*'

    【讨论】:

      猜你喜欢
      • 2013-02-10
      • 2011-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-15
      • 1970-01-01
      相关资源
      最近更新 更多