【问题标题】:linq to entities generated sqllinq 到实体生成的 sql
【发布时间】:2010-10-09 06:35:03
【问题描述】:

我在 ado.net 实体框架中的 linq to 实体方面遇到了一些问题。基本上我在做的是这样的:

var results = (from c in companies
    where c.Name.StartsWith(letter)
    select c);

这会被翻译成 SQL,如下所示:

WHERE (CAST(CHARINDEX(@p, [Extent1].[Name]) AS int)) = 1

这很好,但我的表有数百万条记录,所以运行速度非常慢。我需要它生成的是这样的:

WHERE Name LIKE @p + '%'

我搜索了高低,找不到任何解决方案,除了使用存储过程或使用实体 sql...

有没有办法通过 linq 做到这一点?可能是通过某种方式将 linq 扩展到实体 linq 提供程序,或者以某种方式拦截命令树或生成的查询?

【问题讨论】:

  • 正是这种事情让我非常不愿意放弃我的存储过程层,转而支持任何生成 SQL 的东西。

标签: c# sql linq linq-to-entities sql-like


【解决方案1】:

哇,这真是一种奇怪的做法!请注意,LINQ-to-SQL(在这种情况下)使用 LIKE @p0 + '%'... 非常奇怪。

您使用的是哪个 EF 提供程序(数据库)? SQL Server?

正如你所说,存储过程将完成这项工作,但你不应该必须这样做......非常非常奇怪......

【讨论】:

  • 是的,我使用的是 SQL Server 2005。根据我的阅读,LINQ to SQL 提供了一个 SqlMethods 类,该类公开了 SQL 函数和运算符,例如 LIKE,但在 LINQ to Entities 中没有这样的东西。去图...
【解决方案2】:

我不是 SQL 专家,但我猜测这两种语法:

WHERE (CAST(CHARINDEX(@p, [Extent1].[Name]) AS int)) = 1

WHERE Name LIKE @p + '%'

将导致表扫描或理想情况下的索引扫描。最重要的是,他们将执行相同的操作。我通过查看下面的执行计划验证了这一点。最重要的是,您需要重新考虑您的数据库架构或您执行搜索的方式。这不是 LINQ 问题。

一个可能需要改进的地方:确保您已为正在搜索的列编制索引。

alt text http://download.binaryocean.com/plan1.gif

alt text http://download.binaryocean.com/plan2.gif

【讨论】:

  • 如果您在 Note/Name 列上有索引并且基数不太低,它将用于 LIKE 'a%' 查询。我不确定查询优化器能否将索引用于 CAST(CHARINDEX()) 操作。
  • 我的数据库的名称列上有一个索引。 LIKE 进行索引扫描,生成的 SQL (CHARINDEX) 进行表扫描,这就是它需要这么长时间的原因。
  • 底线他们将执行相同的操作。错误的。在存在索引的情况下,它们的性能差异很大。
【解决方案3】:

“字母”是字符吗?如果你把它变成一个字符串,会发生什么?

var results = (from c in companies
    where c.Name.StartsWith(letter.ToString())
    select c);

【讨论】:

    【解决方案4】:

    我尝试改用这种语法

    Name.Substring(0, 1) == "E"
    

    生成这条 SQL

    WHERE N'E' = (SUBSTRING([Name], 0 + 1, 1))
    

    也许这样更有效?

    【讨论】:

      【解决方案5】:

      这是带有 Linq to Entities 的 known issue。与 LIKE 不同,显然这个结构不使用索引。

      我们在使用 Substring(转换为 SUBSTRING)方面取得了一些成功。执行计划类似,但在我们的例子中查询执行得更快。

      这是另一个“我确定它将在 EF 2 中修复”... :-(

      【讨论】:

        【解决方案6】:

        你可以很容易地在 Link to Entities 中使用真实的like

        以下是使它工作的必要条件:

        添加

            <Function Name="String_Like" ReturnType="Edm.Boolean">
              <Parameter Name="searchingIn" Type="Edm.String" />
              <Parameter Name="lookingFor" Type="Edm.String" />
              <DefiningExpression>
                searchingIn LIKE lookingFor
              </DefiningExpression>
            </Function>
        

        到你的 EDMX 在这个标签中:

        edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/Schema

        还要记住&lt;schema namespace="" /&gt; 属性中的命名空间

        然后在上面的命名空间中添加一个扩展类:

        public static class Extensions
        {
            [EdmFunction("DocTrails3.Net.Database.Models", "String_Like")]
            public static Boolean Like(this String searchingIn, String lookingFor)
            {
                throw new Exception("Not implemented");
            }
        }
        

        此扩展方法现在将映射到 EDMX 函数。

        更多信息在这里:http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

        【讨论】:

          猜你喜欢
          • 2011-07-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多