【发布时间】:2012-10-14 21:43:12
【问题描述】:
我有几个关于 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 毫秒内完成。
更新
这是结果。
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)
更新
刚刚找到这个
http://www.sqlite.org/optoverview.html
4.0 LIKE 优化
The ESCAPE clause cannot appear on the LIKE operator
那我该怎么办呢?
我理解对了吗?我无法在SQLite 中使用LIKE 运算符搜索包含通配符的字符串。我说通配符是指_%^!
这是不可能的,因为我无法逃脱它们。 其实可以,但是这种情况下不能使用索引,所以查询效率不高。
我说的对吗?
【问题讨论】:
-
我不熟悉 SQLite 细节,但大多数 DBMS 通常会独立于绑定参数 value 准备查询 - 事实上,查询准备甚至可以在参数之前进行值是已知的。因此,
LIKE @Pattern无法针对索引进行优化,因为@Pattern可能是“%suffix”。正如您已经指出的那样,解决方案是动态构建查询 - 坦率地说,我不明白为什么 ESCAPE 会搞砸。 -
是的,我也没有看到它,但这就是正在发生的事情。我可以理解为什么它不使用索引进行连接,但是
escape有什么问题?不幸的是,我需要转义%符号以允许搜索以%windir%之类的开头的字符串。 -
顺便说一句,它也不使用以下索引。
SELECT * FROM [Table] WHERE [Name] LIKE 'Text' || '%' -
@axe ESCAPE 的行为似乎是 SQLite 的限制。引用The SQLite Query Planner: "由 LIKE 或 GLOB 运算符组成的术语有时可用于约束索引。这种使用有很多条件:... 3. ESCAPE 子句不能出现在 LIKE 运算符上。”
-
@Branko Dimitrijevic:是的,这已经在我的问题中引用了。那么解决方案是什么?查询工作 40 秒显然是不可接受的。另一方面,不允许用户搜索包含下划线的字符串也是不可接受的。
标签: c# .net performance sqlite indexing