如何加快在大型sqlite数据库中的搜索速度

时间:2014-04-16 08:50:47

标签: c# linq sqlite windows-phone

我正在尝试开发一个能够在大型(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是用户输入的两个单词。

提前谢谢你,

纳丁

1 个答案:

答案 0 :(得分:0)

此查询存在多个问题。

第一个是ToLower转换。在SQL中,这被转换为类似lower(firstname) = :input1的东西,这可以防止sqlite在firstname列上使用索引(如果存在这样的索引)。在这种情况下,需要sqlite扫描所有300k记录,而不是直接使用索引查找一小部分记录。

要缓解此问题,您可以向contactslowercase_firstnamelowercase_lastname添加其他列,并在插入时触发器中设置firstnamelastname的值更新联系表。您应该为此列添加索引并按其过滤,以避免在where子句中调用lower

第二个问题是使用Contains。我不确定LINQ究竟是如何将其转换为SQL的,但它没有太多选择。它要么

  1. 翻译为:firstname like '%<input1>%'
  2. 或内存过滤
  3. 第二个选项需要从数据库中读取所有记录,但这不会很快。 第一个选项不使用firstname列上的现有索引,并且需要全表扫描。

    不幸的是,目前sqlite无法像使用索引一样进行搜索。所以这不可能很快。

    一种选择是禁止在名字和姓氏内搜索,只允许按名字的第一个字母进行搜索。因此,如果input1 = Rita用户能够找到Rita而不是Margarita。有了这个限制,可以通过发出范围查询来搜索使用索引,例如lowercase_firstname between 'Rita' and 'Rita{'(此处{z后面的字母)。 This应该帮助你在LINQ中表达。