【问题标题】:LINQ to SQL will not generate sargable queryLINQ to SQL 不会生成 sargable 查询
【发布时间】:2013-07-31 19:24:53
【问题描述】:

我正在使用 LINQ To Sql(不是实体框架)、System.Data.Linq.DataContext 库、访问 SQL Server 2005 数据库并使用 .Net Framework 4。

表 dbo.Dogs 有一个 CHAR(1) NULL 类型的“Active”列。如果我直接编写 SQL,查询将是:

SELECT * FROM dbo.Dogs where Active = 'A';

LINQ 查询是这样的:

from d in myDataContext.Dogs where d.Active == 'A' select d;

从上述 LINQ 查询生成的 SQL 将 Active 字段转换为 UNICODE。这意味着我无法使用 dbo.Dogs.Active 列上的索引,从而显着降低查询速度:

SELECT [t0].Name, [t0].Active
FROM [dbo].[Dog] AS [t0]
WHERE UNICODE([t0].[Active]) = @p1

我能做些什么来阻止 Linq to Sql 插入 UNICODE() 调用(从而失去我对 dogs.Active 的索引的好处)?我尝试使用 EntityFunctions.AsNonUnicode() 方法包装参数,但这没有用(它在生成的 sql 中将 CONVERT() 插入到 NVARCHAR 而不是 UNICODE() ),例如:

...where d.Active.ToString() == EntityFunctions.AsNonUnicode('A'.ToString());

【问题讨论】:

  • 这是我个人的看法,但它是基于我自己的经验——不要使用 Linq2SQL 它会产生可怕的 SQL 语句,而且你的 Linq 查询增长得越复杂——发出的最优 SQL 语句就越少.不确定其他 ORM,但这个是邪恶的。
  • 是的。我应该补充一点,我没有使用 Linq to Sql,因为我比较了不同的 ORM 并决定 Linq to Sql 是最好的。我正在维护旧代码。
  • 虽然 ORM 是非常容易泄漏的抽象,但我不同意永远不要使用它们的跨板声明。该决定很大程度上取决于用例。那里有明显的价值,也有明显的缺点。
  • 好吧,如果你根本不关心性能,我猜 ORM 没问题。
  • 和内存一样,数据库也是共享资源。每个错误的查询本身都不是问题。但如果作为一个整体,你将面临千刀万剐的死亡。

标签: c# .net linq-to-sql


【解决方案1】:

Linq 旨在使编写查询更容易,但并不总是生成最佳 SQL。有时,当需要高性能时,直接针对数据库编写原始 SQL 会更有效,Linq 数据上下文支持将 SQL 结果映射到实体,就像 linq 一样。 在你的情况下,我建议写:

IEnumerable<Dog> results = db.ExecuteQuery<Dog>(
                           "SELECT * FROM dbo.Dogs where Active = {0}", 
                           'A');

【讨论】:

  • 或者写一个存储过程
  • @LoztInSpace 当然也可以,但这并不费力。存储过程是如此 90 年代 ;-)
  • 我希望我也可以将其标记为答案,两者都有效,而且我实际上会在不同的地方实施。
【解决方案2】:

这是一个老问题,但我最近遇到了这个问题。

而不是写

from d in myDataContext.Dogs where d.Active == 'A' select d;

from d in myDataContext.Dogs where d.Active.Equals('A') select d;

这将产生所需的 SQL,而无需求助于其他答案中提到的任何“黑客”。我不能肯定地说为什么。

我已经发布了as a question,所以我们会看看是否能得到任何好的答案。

【讨论】:

    【解决方案3】:

    对于将 LINQ 查询转换为 SQL 语句的方式,您无能为力,但您可以编写一个包含查询的存储过程,并将该 SP 作为 LINQ2SQL 函数调用。这样您就可以充分利用 SQL Server 优化

    【讨论】:

    • 或者只是编写一个内联 SQL 查询,它会像 linq 语句一样映射到 DTO。
    • 我不知道 Linq2SQL 支持内联查询。是否有关于该功能的文档?
    • @Magnus 非常酷,谢谢!总能学到一些东西。我认为你应该输入这个作为答案,因为这个套件 OP 需要更多。
    【解决方案4】:

    您可以做一些小技巧(因为 LINQ to SQL 和 EF 经常需要这样做)。在 dbml 中将属性声明为 NCHAR。我希望这将消除进行UNICODE 转换的需要。我们正在以一种良性的方式欺骗​​ L2S。

    也许您还需要插入 EntityFunctions.AsNonUnicode 调用以使右侧成为非 unicode 类型。

    您也可以尝试将列映射为varchar

    【讨论】:

    • 破解 dbml 以将 "CHAR(1)" 更改为 "VARCHAR(1)" 成功了,感谢您的建议。当然,这种方法的缺点是再也无法使用设计器来更新 dbml 文件,但对于我正在使用的遗留应用程序来说,这不是问题。
    • 或者,使用.Equals 而不是== 生成没有UNICODE 函数调用的SQL。至于为什么,我不知道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    相关资源
    最近更新 更多