我正在尝试开发一个能够在大型(300,000人)sqlite数据库中搜索人员的Windows Phone应用程序。 问题是找一个人需要半分钟。
您是否知道如何更快地进行搜索?
这是我的代码:
var queryname = conn.Table<contacts>().Where(
x =>
(
((x.firstName.ToLower() == input1) && (x.lastName.ToLower() == input2))
|| ((x.firstName.ToLower() == input2) && (x.lastName.ToLower() == input1))
|| ((x.firstName.ToLower() == input1) && (x.lastName.ToLower().Contains(input2)))
|| ((x.lastName.ToLower().Contains(input1)) && (x.firstName.ToLower() == input2))
));
var resultname = await queryname.ToListAsync();
Person1.Content = null;
foreach (var item in resultname)
{
outputname = string.Format("{0} {1}", item.firstName, item.lastName);
}
输入1和2是用户输入的两个单词。
提前谢谢你,
纳丁
答案 0 :(得分:0)
此查询存在多个问题。
第一个是ToLower
转换。在SQL中,这被转换为类似lower(firstname) = :input1
的东西,这可以防止sqlite在firstname列上使用索引(如果存在这样的索引)。在这种情况下,需要sqlite扫描所有300k记录,而不是直接使用索引查找一小部分记录。
要缓解此问题,您可以向contacts
表lowercase_firstname
和lowercase_lastname
添加其他列,并在插入时触发器中设置firstname
和lastname
的值更新联系表。您应该为此列添加索引并按其过滤,以避免在where子句中调用lower
。
第二个问题是使用Contains
。我不确定LINQ究竟是如何将其转换为SQL的,但它没有太多选择。它要么
firstname like '%<input1>%'
第二个选项需要从数据库中读取所有记录,但这不会很快。 第一个选项不使用firstname列上的现有索引,并且需要全表扫描。
不幸的是,目前sqlite无法像使用索引一样进行搜索。所以这不可能很快。
一种选择是禁止在名字和姓氏内搜索,只允许按名字的第一个字母进行搜索。因此,如果input1 = Rita用户能够找到Rita
而不是Margarita
。有了这个限制,可以通过发出范围查询来搜索使用索引,例如lowercase_firstname between 'Rita' and 'Rita{'
(此处{
是z
后面的字母)。 This应该帮助你在LINQ中表达。