【问题标题】:sqlite query slow, how to optimize (using linq to entities)sqlite 查询慢,如何优化(使用 linq 到实体)
【发布时间】:2015-06-22 14:41:14
【问题描述】:

我已经使用了几次 MS SQL 服务器,但在使用 linq 到实体进行查询时还没有遇到速度问题。这一次,我使用 sqlite,将整个数据库与应用程序一起发送。

我有一个包含 4 个搜索字段的 winforms 应用程序。我的目标是设计搜索以使结果反映单个字段或多个字段(根据哪些字段具有搜索词构建查询)。

目前,我的查询有效,但需要相当长的时间才能针对 sqlite 数据库执行。特别是在第一次运行时。我认为这是因为 sqlite 背后没有强大的服务器,结果在本地处理并加载到内存中。我认为数据库正在为其自身编制索引,或者必须第一次构建某种缓存。

我如何优化我的 linq 查询以使我不必将整个表加载到内存中,然后限制结果,但在加载表时限制结果?

    public List<ResultGridviewModel> GetChartsFromSearch(string patientID, string firstName, string lastName, DateTime? dateOfBirth)
    {
        using (var _dataContext = new dbEntities())
        {

            var records = (from c in _dataContext.charts
                          select new ResultGridviewModel 
                          {
                              AltID = c.AltID,
                              FirstName = c.FirstName,
                              LastName = c.LastName,
                              DateOfBirth = c.DateOfBirth,
                              Description = c.Description,
                              ServiceDateTime = c.ServiceDateTime
                          });


            // AltID (PatientID)
            if (!string.IsNullOrEmpty(patientID))
            {
                records = records.Where(x => x.AltID.Contains(patientID.Trim().ToUpper()));
            }

            // First Name
            if (!string.IsNullOrEmpty(firstName))
            {
                records = records.Where(x => x.FirstName.Contains(firstName.Trim().ToUpper()));
            }

            // Last Name
            if (!string.IsNullOrEmpty(lastName))
            {
                records = records.Where(x => x.LastName.Contains(lastName.Trim().ToUpper()));
            }

            // Date Of Birth
            if (dateOfBirth != null)
            {
                records = records.Where(x => x.DateOfBirth == dateOfBirth);
            }


            return records.ToList();
        }
    }

我已将索引应用于数据库本身的这些字段,但我觉得问题出在我的查询中。关于重构优化的任何建议?

截至目前,数据库约有 35 万条记录,并且可能会变得更大。最终,我将停止向其中添加记录,但我们假设粗略估计它将有大约 70 万条记录

【问题讨论】:

    标签: c# linq entity-framework sqlite


    【解决方案1】:

    最大的优化是将Contains 更改为StartsWith。这相当于从name like '%search%' 更改为name like 'search%'。否则 SQLite 不能完全使用你放在列上的索引,你基本上是在搜索整个表。

    // First Name
    if (!string.IsNullOrEmpty(firstName))
    {
      firstName = firstName.Trim().ToUpper();
      records = records.Where(x => x.FirstName.StartsWith(firstName));
    }
    

    【讨论】:

    • 这确实缩短了查询时间。由于数据库的大小,我担心这可能与它所获得的一样好,但在从 .Contains() 切换到 .StartsWith() 之后,这里有一个改进。
    • @CodyHicks - 你遇到什么样的速度?当您尝试使用长字符串进行搜索时会很慢吗? IE。如果你搜索cody?
    • 机器重启后第一次运行应用程序时速度最慢。大概慢了2-3分钟。随后的搜索速度非常快,最多约 3 秒。这是当我用长字符串运行搜索时,是的。当我用日期搜索时,无论如何结果都是 ~1-2 秒。我的所有字符串列的数据库索引是 CREATE INDEX string_index ON table (ColumnName COLLATE NOCASE); 我使用带有 DateTime 的 BINARY 排序规则
    • 有趣的是,我将所有排序规则都更改为 BINARY,它将我的初始查询时间增加到第一次运行约 10 秒,随后运行几乎没有。我确信这会没问题,因为所有字符串数据都将在精确的大小写中进行搜索,因此不需要NOCASE。我在想NOCASE 需要更长的时间,因为它必须在数据库级别比较大写/小写(更多处理时间)。
    • 就像 Aducci 所说的, Contains 不能通过索引进行优化(您可以在 SQL Server 上使用全文索引来做一些事情,但这很棘手)。您也可以从 EF 在数据库上运行的查询开始。如果在 records.ToList() 之前停止程序,如果查看记录,则记录包含 EF 在调用 ToList() 时将发送到 SQLite 的查询。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    相关资源
    最近更新 更多