在不牺牲索引使用的情况下,在SQLite LIKE中转义通配符(%,_)?
我对SQLite查询有几个问题。 实际上我开始认为SQLite不是为超过10行的表设计的,实际上,SQLite是一场噩梦。
以下查询
SELECT * FROM [Table] WHERE [Name] LIKE 'Text%'
它工作正常。 EXPLAIN
显示使用索引并在大约70ms
后返回结果。
现在我需要从.NET SQLite驱动程序运行此查询,所以我正在更改查询
SELECT * FROM [Table] WHERE [Name] LIKE @Pattern || '%'
索引未使用。 当我在任何SQLite工具中运行以下查询时,也不使用索引
SELECT * FROM [Table] WHERE [Name] LIKE 'Text' || '%'
所以我猜SQLite没有实现任何类型的预处理逻辑。
好。 让我们试着解决它,我仍然绑定变量并执行以下操作
SELECT * FROM [Table] WHERE [Name] LIKE @Pattern
但现在我将%
通配符附加到我的模式字符串的末尾,就像这样
command.Parameters.Add(new SQLiteParameter("@Pattern", pattern + '%'));
它工作得很慢。 我不能说为什么,因为当我从SQLite工具运行此查询时,它工作正常,但是当我从.NET代码绑定此变量时,它工作缓慢。
好。 我还在努力解决这个问题。 我正在摆脱模式参数绑定并动态构建此条件。
pattern = pattern.Replace("'", "''"); pattern = pattern.Replace("%", "\\%"); where = string.Format("LIKE '{0}%' ESCAPE '\\'", pattern);
索引不再使用。 由于ESCAPE
它没有被使用。 当我跑步时,我看到了
EXPLAIN QUERY PLAN SELECT * FROM [Table] WHERE [Name] LIKE 'Text%' ESCAPE '\'
一旦我删除ESCAPE
它就会再次开始使用索引,查询结束时间为60-70毫秒。
UPDATE
结果如下。
EXPLAIN QUERY PLAN SELECT * FROM [RegistryValues] WHERE [ValueName] LIKE 'windir%' ESCAPE '\'
SCAN TABLE RegistryValues (~3441573 rows)
没有ESCAPE
那个
EXPLAIN QUERY PLAN SELECT * FROM [RegistryValues] WHERE [ValueName] LIKE 'windir%'
SEARCH TABLE RegistryValues USING INDEX IdxRegistryValuesValueNameKeyIdKeyHiveFileId (ValueName>? AND ValueName<?) (~31250 rows)
UPDATE
刚发现这个
http://www.sqlite.org/optoverview.html
4.0 LIKE优化
The ESCAPE clause cannot appear on the LIKE operator
那我该怎么办呢?
我理解对吗? 我无法在SQLite
使用LIKE
运算符搜索包含通配符的字符串。 通过说通配符我的意思是_
%
^
!
这是不可能的,因为我无法摆脱他们。 实际上我可以,但在这种情况下我不能使用索引,因此查询效率不高。
我对吗?
当%
在最后时,索引只能与LIKE
子句一起使用,以便SQLite可以将其重写为两个简单的比较(如EXPLAIN
输出中所示)。
因此,要获得相同的效果,请自行编写比较。 这要求您构造一些保证比任何匹配值“更大”的字符串(谨防非ASCII字符)。 代替:
... WHERE Name LIKE 'Text%'
使用:
... WHERE Name BETWEEN 'Text' AND 'Textzzzzzzzzzzzzz'
或者,作为参数:
... WHERE Name BETWEEN @Pattern AND @Pattern || 'zzzzzzzzzz'
(这个构造永远不需要逃脱。:)
确保将查询包装在事务中。 我一直在通过没有它的库进行一些查询,并添加它增加了10倍的速度。
可能是性能问题的最佳资源: 提高SQLite的每秒INSERT性能?