【问题标题】:Using EntityFramework for search is MASSIVELY slow. How can I improve the speed of the query?使用 EntityFramework 进行搜索非常慢。如何提高查询速度?
【发布时间】:2015-09-18 05:25:29
【问题描述】:

我在 MVC 4 网站中使用 Entity Framework 5.0.0。

网站的一部分允许用户在数据库中搜索记录。搜索最多可以包含 10 个搜索条件,这些条件可能涉及(生成 where 子句)4-5 个表并从 14 个表返回数据。

搜索页面提供了许多可供搜索的字段:关键字、标题、日期等。

搜索功能允许搜索词的“或”或“与”组合。 例如,可以要求 Title AND Date 匹配,或者 Title OR Date 匹配。

查询看起来类似于:

Dim searchQuery As IQueryable(Of MainTableClass) = Nothing
Dim query As IQueryable(Of MainTableClass) = Nothing
Dim queries As List(Of IQueryable(Of MainTableClass)) = New List(Of IQueryable(Of MainTableClass))

Using database As DataContext = new DataContext
    searchQuery = ( From x In database.MainTableClasses. _
                            Include("Secondary.Third.Fourth"). _
                            Include("Secondary.Fifth.Sixth"). _
                            Include("Eighth"). _
                            Include("Nine.Ten.Eleven.Twelve"). _
                            Include("Thirteen.Fourteen")
                Select x)
    '   Some things here to limit the initial set that searchQuery returns
    '   eg:  searchQuery = searchQuery.Where(Function(m) m...blah blah)

    If Not String.IsNullOrEmpty(model.Title) Then
        query = (From x In database.MainTableClasses Where x.Secondary.Title = model.Title Select x)
        queries.Add(query)
    End If

    If Not Nothing Is model.Date Then
        query = (   From x In database
                    Where x.Nine.Any(Function(a) model.Date < a.Value)  )
        queries.Add(query)
    End If


    '
    '   Now to combine the results
    '
    For Each item As IQueryable(Of MainTableClass) In queries
        Select Case model.SearchType
            Case SearchType.OR      '   Or the search terms
                searchQuery = searchQuery.Union(item)

            Case Else               '   And the search terms
                searchQuery = searchQuery.Intersect(item)

        End Select
    Next

    '
    '   Run the query
    '
    results = searchQuery.ToList
End Using

问题在于,Linq 将实际查询转换为 5700 行 SQL,并且在 Azure 最大的 SQL 数据库产品上运行需要 9 秒以上。完全不能接受。我可以在不到 30 行的时间内用 SQL 手动编写主要搜索查询。

那么,我能做些什么来重构这个查询,让它运行得更快呢? EF/Linq 不是正确的工具吗?我在这里做错了什么吗?

【问题讨论】:

  • 这不是适合这项工作的工具。您最好在某个字段上创建一个全文索引,该字段将包含您需要搜索的连接数据,然后使用entityframework.info/Home/FullTextSearch 中描述的解决方案。否则,您将不得不选择 Lucene / ElasticSearch 等。
  • 这是一个完全不可接受的解决方案。如果我要手动编写 SQL,它会很快工作。这些表中的数据不断变化 - 创建和维护一个将搜索数据连接在一起的字段是不可能的。
  • 您能解释一下手工生成的查询和 Linq 生成的查询之间的区别吗?在我看来,您可以避免使用许多 Include 语句,并可能稍后重新加载引用。这可以是一个开始..
  • 主要区别在于 LINQ 查询将近 5700 行,而手写查询大约 10 行。稍后我会写出我的解决方案。

标签: sql-server performance entity-framework linq-to-entities entity-framework-5


【解决方案1】:

所以我想出的解决方案是手工编写 SQL,让 Linq-To-SQL 执行 ORM 函数来填充我的数据模型:

Dim sql As String = "SELECT ... FROM Classes WHERE ..."
Dim model As SearchResultsModel = Nothing

model = database.Classes.SqlQuery(sql).ToList

【讨论】:

    猜你喜欢
    • 2016-03-12
    • 1970-01-01
    • 2014-10-20
    • 1970-01-01
    • 2019-08-13
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多