Can the LIKE statement be optimized to not do full table scans?

旧街凉风 提交于 2019-11-27 19:36:56

问题


I want to get a subtree from a table by tree path.

the path column stores strings like:

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

If I try to select all records that start with a certain path:

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

it tells me that the table is scanned, even though the path column is indexed :(

Is there any way I could make LIKE use the index and not scan the table?

I found a way to achieve what I want with closure table, but it's harder to maintain and writes are extremely slow...


回答1:


To be able to use an index for LIKE in SQLite,

  1. the table column must have TEXT affinity, i.e., have a type of TEXT or VARCHAR or something like that; and
  2. the index must be declared as COLLATE NOCASE (either directly, or because the column has been declared as 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<?)
    

The second restriction could be removed with the case_sensitive_like PRAGMA, but this would change the behaviour of LIKE. Alternatively, one could use a case-sensitive comparison, by replacing LIKE 'foo/%' with GLOB 'foo/*'.




回答2:


LIKE has strict requirements to be optimizable with an index (ref).

If you can relax your requirements a little, you can use lexicographic ordering to get indexed lookups, e.g.

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

where 0 is the lexigographically next character after /.

This is essentially the same optimization the optimizer would do for LIKEs if the requirements for optimization are met.



来源:https://stackoverflow.com/questions/20423387/can-the-like-statement-be-optimized-to-not-do-full-table-scans

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!