190

我查看了 StackOverflow 上的“LINQ 初学者指南”帖子(LINQ 初学者指南),但有一个后续问题:

我们即将启动一个新项目,其中几乎我们所有的数据库操作都将是相当简单的数据检索(项目的另一部分已经写入数据)。到目前为止,我们的大多数其他项目都使用存储过程来处理这些事情。但是,如果更有意义,我想利用 LINQ-to-SQL。

所以,问题是:对于简单的数据检索,哪种方法更好,LINQ-to-SQL 还是存储过程?有什么具体的优点或缺点吗?

谢谢。

4

22 回答 22

194

LINQ 相对于存储过程的一些优点:

  1. 类型安全:我想我们都明白这一点。
  2. 抽象:对于LINQ-to-Entities尤其如此。这种抽象还允许框架添加您可以轻松利用的其他改进。 PLINQ是向 LINQ 添加多线程支持的示例。添加此支持的代码更改很少。执行这种仅调用 sprocs 的数据访问代码会困难得多。
  3. 调试支持:我可以使用任何 .NET 调试器来调试查询。使用存储过程,您无法轻松调试 SQL,并且这种体验很大程度上取决于您的数据库供应商(MS SQL Server 提供了一个查询分析器,但通常这还不够)。
  4. 供应商不可知论:LINQ 可与大量数据库一起使用,支持的数据库数量只会增加。由于不同的语法或功能支持(如果数据库完全支持 sprocs),Sprocs 并不总是在数据库之间可移植。
  5. 部署:其他人已经提到了这一点,但是部署单个程序集比部署一组存储过程更容易。这也与#4 相关。
  6. 更简单:您不必学习 T-SQL 来进行数据访问,也不必学习调用存储过程所需的数据访问 API(例如 ADO.NET)。这与#3 和#4 有关。

LINQ vs sprocs 的一些缺点:

  1. 网络流量:当 LINQ 发送整个查询时,sprocs 只需要通过线路序列化 sproc-name 和参数数据。如果查询非常复杂,这可能会变得非常糟糕。然而,LINQ 的抽象允许微软随着时间的推移改进这一点。
  2. 不太灵活:Sprocs 可以充分利用数据库的功能集。LINQ 的支持往往更通用。这在任何类型的语言抽象中都很常见(例如 C# 与汇编程序)。
  3. 重新编译:如果需要更改数据访问方式,则需要重新编译、版本化和重新部署程序集。Sprocs有时可以让 DBA 调整数据访问例程,而无需重新部署任何东西。

安全性和可管理性也是人们争论的话题。

  1. 安全性:例如,您可以通过直接限制对表的访问来保护您的敏感数据,并将 ACL 放在存储过程中。但是,使用 LINQ,您仍然可以限制对表的直接访问,而是将 ACL 放在可更新的表视图上以达到类似的目的(假设您的数据库支持可更新的视图)。
  2. 可管理性:使用视图还可以使您的应用程序不受模式更改的影响(如表规范化)。您可以更新视图,而无需更改数据访问代码。

我曾经是一个大 sproc 人,但我开始倾向于将 LINQ 作为一个更好的选择。如果在某些领域存储过程明显更好,那么我可能仍会编写存储过程,但使用 LINQ 访问它。:)

于 2008-08-26T20:04:51.347 回答
80

由于 DBA 多年来一直在喋喋不休的所有原因,我通常支持将所有内容都放入存储过程中。在 Linq 的情况下,确实不会有简单的 CRUD 查询的性能差异。

但是在做出这个决定时要记住一些事情:使用任何 ORM 都会使您与数据模型紧密结合。DBA 不能在不强制您更改已编译代码的情况下更改数据模型。使用存储过程,您可以在一定程度上隐藏这些类型的更改,因为从过程返回的参数列表和结果集代表它的契约,只要仍然满足该契约,就可以更改内部结构.

而且,如果 Linq 用于更复杂的查询,则调整数据库将变得更加困难。当存储过程运行缓慢时,DBA 可以完全专注于孤立的代码,并且有很多选择,只是为了在他/她完成时仍然满足合同。

我见过很多很多情况下,应用程序中的严重问题是通过更改存储过程中的模式和代码来解决的,而无需对已部署的编译代码进行任何更改。

也许混合方法对 Linq 会很好?当然,Linq 可以用来调用存储过程。

于 2008-08-18T12:59:51.457 回答
64

Linq 到 Sql。

Sql server 将缓存查询计划,因此存储过程没有性能提升。

另一方面,您的 linq 语句将在逻辑上成为您的应用程序的一部分并与您的应用程序一起测试。Sprocs 总是有点分离,更难维护和测试。

如果我现在从头开始开发一个新应用程序,我只会使用 Linq,而不是存储过程。

于 2008-08-18T12:40:52.447 回答
40

对于基本的数据检索,我会毫不犹豫地选择 Linq。

自从搬到 Linq 后,我发现了以下优势:

  1. 调试我的 DAL 从未如此简单。
  2. 架构更改时的编译时间安全是无价的。
  3. 部署更容易,因为所有内容都编译成 DLL。不再需要管理部署脚本。
  4. 因为 Linq 可以支持查询任何实现 IQueryable 接口的东西,所以您将能够使用相同的语法来查询 XML、对象和任何其他数据源,而无需学习新的语法
于 2008-08-18T13:08:31.190 回答
27

LINQ 会使过程缓存膨胀

如果应用程序正在使用 LINQ to SQL,并且查询涉及使用长度可变的字符串,则 SQL Server 过程缓存将因每个可能的字符串长度的查询版本而变得臃肿。例如,考虑以下针对 AdventureWorks2008 数据库中的 Person.AddressTypes 表创建的非常简单的查询:

var p = 
    from n in x.AddressTypes 
    where n.Name == "Billing" 
    select n;

var p = 
    from n in x.AddressTypes 
    where n.Name == "Main Office" 
    select n;

如果这两个查询都运行,我们将在 SQL Server 过程缓存中看到两个条目:一个与 NVARCHAR(7) 绑定,另一个与 NVARCHAR(11) 绑定。现在想象一下,如果有成百上千个不同的输入字符串,都具有不同的长度。对于完全相同的查询,过程缓存将不必要地填充各种不同的计划。

更多信息:https ://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=363290

于 2008-08-28T16:11:55.537 回答
18

我认为 pro LINQ 论点似乎来自没有数据库开发历史的人(通常)。

特别是如果使用像 VS DB Pro 或 Team Suite 这样的产品,这里提出的许多论点都不适用,例如:

更难维护和测试:VS 提供完整的语法检查、样式检查、引用和约束检查等。它还提供完整的单元测试功能和重构工具。

LINQ 使真正的单元测试成为不可能,因为(在我看来)它没有通过 ACID 测试。

在 LINQ 中调试更容易:为什么?VS 允许从托管代码完全介入并定期调试 SP。

编译成单个 DLL 而不是部署脚本:VS 再次发挥作用,它可以构建和部署完整的数据库或进行数据安全的增量更改。

不必使用 LINQ 学习 TSQL:不,您不需要,但您必须学习 LINQ - 好处在哪里?

我真的不认为这是一个好处。能够单独更改某些东西在理论上可能听起来不错,但仅仅因为更改符合合同并不意味着它会返回正确的结果。为了能够确定正确的结果是什么,您需要上下文,并从调用代码中获取该上下文。

嗯,松散耦合的应用程序是所有优秀程序员的最终目标,因为它们确实增加了灵活性。能够独立地改变事物是很棒的,而且你的单元测试将确保它仍然返回适当的结果。

在大家不高兴之前,我认为 LINQ 有它的位置并且有一个美好的未来。但是对于复杂的数据密集型应用程序,我认为它还没有准备好取代存储过程。这是我今年在 TechEd 获得 MVP 的回应(他们将保持匿名)。

编辑:LINQ to SQL 存储过程方面的事情我仍然需要阅读更多内容 - 取决于我发现我可能会改变我上面的诽谤;)

于 2008-09-12T04:42:23.510 回答
17

LINQ 是新的并且有它的位置。LINQ 并不是为了取代存储过程而发明的。

在这里,我将重点介绍一些性能神话和缺点,仅针对“LINQ to SQL”,当然我可能完全错了;-)

(1)人们说LINQ语句可以在SQL server中“缓存”,所以不会损失性能。部分正确。“LINQ to SQL”实际上是将 LINQ 语法转换为 TSQL 语句的运行时。所以从性能的角度来看,硬编码的 ADO.NET SQL 语句与 LINQ 没有区别。

(2)举个例子,一个客服UI有“转帐”功能。这个函数本身可能会更新 10 个数据库表并一次性返回一些消息。使用 LINQ,您必须构建一组语句并将它们作为一个批次发送到 SQL 服务器。这个翻译后的 LINQ->TSQL 批处理的性能几乎无法与存储过程相提并论。原因?因为您可以使用内置的 SQL 分析器和执行计划工具来调整存储过程中语句的最小单元,所以在 LINQ 中不能这样做。

关键是,在谈论单个 DB 表和少量数据 CRUD 时,LINQ 与 SP 一样快。但是对于更复杂的逻辑,存储过程更容易调整性能。

(3)“LINQ to SQL”很容易让新手引入性能猪。任何高级 TSQL 人员都可以告诉您何时不使用 CURSOR(基本上,在大多数情况下,您不应该在 TSQL 中使用 CURSOR)。使用 LINQ 和带有查询的迷人的“foreach”循环,对于新手来说编写这样的代码非常容易:

foreach(Customer c in query)
{
  c.Country = "Wonder Land";
}
ctx.SubmitChanges();

你可以看到这个简单而体面的代码是如此吸引人。但在后台,.NET 运行时只是将其转换为更新批处理。如果只有 500 行,这是 500 行 TSQL 批处理;如果有百万行,这是一个成功。当然,有经验的用户不会用这种方式来做这项工作,但关键是,这种方式很容易沦陷。

于 2008-12-03T05:40:53.513 回答
14

最好的代码是无代码,使用存储过程,您必须在数据库中编写至少一些代码,并在应用程序中编写代码来调用它,而使用 LINQ to SQL 或 LINQ to Entities,您不必编写任何额外的代码除了实例化上下文对象之外的任何其他 LINQ 查询的代码。

于 2008-08-18T12:45:13.140 回答
11

LINQ 在特定于应用程序的数据库和小型企业中肯定占有一席之地。

但是在大型企业中,中央数据库作为许多应用程序的公共数据中心,我们需要抽象。我们需要集中管理安全并显示访问历史。我们需要能够进行影响分析:如果我对数据模型进行小改动以满足新的业务需求,需要更改哪些查询以及需要重新测试哪些应用程序?视图和存储过程给了我这个。如果 LINQ 可以做到所有这些,并使我们的程序员更有效率,我会欢迎它——有没有人有在这种环境中使用它的经验?

于 2008-10-09T14:43:53.843 回答
8

DBA 不能在不强制您更改已编译代码的情况下更改数据模型。使用存储过程,您可以在一定程度上隐藏这些类型的更改,因为从过程返回的参数列表和结果集代表它的契约,只要仍然满足该契约,就可以更改内部结构.

我真的不认为这是一个好处。能够单独更改某些东西在理论上可能听起来不错,但仅仅因为更改符合合同并不意味着它会返回正确的结果。为了能够确定正确的结果是什么,您需要上下文,并从调用代码中获取该上下文。

于 2008-08-19T14:28:23.010 回答
6

恕我直言,RAD = LINQ,RUP = 存储过程。我在一家大型财富 500 强公司工作了很多年,在包括管理在内的多个层面工作,坦率地说,我永远不会聘请 RUP 开发人员来做 RAD 开发。他们是如此孤立,以至于他们对在流程的其他级别做什么的知识非常有限。对于孤立的环境,让 DBA 通过非常具体的入口点控制数据是有意义的,因为坦率地说,其他人不知道完成数据管理的最佳方法。

但大企业在发展的舞台上行动缓慢,代价非常高昂。有时您需要更快地行动以节省时间和金钱,而 LINQ 提供了这一点,甚至更多。

有时我认为 DBA 对 LINQ 有偏见,因为他们觉得它威胁到他们的工作安全。但这就是野兽的本性,女士们先生们。

于 2009-06-30T19:04:17.387 回答
6

我认为您需要使用 procs 来处理任何真实的事情。

A)在 linq 中编写所有逻辑意味着您的数据库不太有用,因为只有您的应用程序可以使用它。

B)我不相信对象建模比关系建模更好。

C) 在 SQL 中测试和开发存储过程比在任何 Visual Studio 环境中的编译编辑周期快得多。您只需编辑、F5 并点击选择,您就可以参加比赛了。

D)存储过程比程序集更容易管理和部署。你只需将文件放在服务器上,然后按 F5 ......

E) Linq to sql 有时仍然会在您不期望的情况下编写蹩脚的代码。

老实说,我认为最终的事情是让 MS 增强 t-sql 以便它可以像 linq 那样隐式地进行连接投影。例如,t-sql 应该知道您是否想做 order.lineitems.part。

于 2012-02-08T16:35:56.237 回答
5

LINQ 不禁止使用存储过程。我已经将混合模式与 LINQ-SQL 和LINQ-storedproc 一起使用。就个人而言,我很高兴我不必编写存储的过程....pwet-tu。

于 2008-08-28T12:39:55.017 回答
4

此外,还有可能 2.0 回滚的问题。相信我,它发生在我身上好几次了,所以我确信它也发生在其他人身上。

我也同意抽象是最好的。除此之外,ORM 的最初目的是使 RDBMS 与 OO 概念很好地匹配。但是,如果在 LINQ 之前一切正常,不得不偏离 OO 概念,那么就搞砸了。概念和现实并不总是很好地结合在一起。IT 中没有激进的狂热分子的空间。

于 2008-10-20T03:14:09.210 回答
4

根据大师的说法,我将 LINQ 定义为摩托车,将 SP 定义为汽车。如果您想短途旅行并且只有少量乘客(在本例中为 2),请优雅地使用 LINQ。但是如果你想去旅行并拥有大乐队,我认为你应该选择SP。

总而言之,选择摩托车还是汽车取决于您的路线(业务)、长度(时间)和乘客(数据)。

希望对你有帮助,我可能错了。:D

于 2011-06-07T07:53:56.430 回答
3

我假设你的意思是 Linq To Sql

对于任何 CRUD 命令,都可以轻松地分析存储过程与任何技术的性能。在这种情况下,两者之间的任何差异都可以忽略不计。尝试对超过 100,000 个选择查询的 5 个(简单类型)字段对象进行分析,以确定是否存在真正的差异。

另一方面,真正的交易破坏者将是您是否愿意将业务逻辑放在数据库中的问题,这是反对存储过程的论据。

于 2008-08-18T12:44:12.300 回答
3

所有这些倾向于 LINQ 的答案主要是在谈论 EASE of DEVELOPMENT,这或多或少与编码质量差或编码懒惰有关。我只是这样。

一些优点或 Linq,我在这里读为,易于测试,易于调试等,但这些与最终输出或最终用户无关。这总是会给最终用户带来性能上的麻烦。在内存中加载许多东西然后在使用 LINQ 时应用过滤器有什么意义?

再次使用 TypeSafety,请注意“我们小心避免错误的类型转换”,我们正试图通过使用 linq 来提高质量。即使在这种情况下,如果数据库中的任何内容发生变化,例如 String 列的大小,那么 linq 需要重新编译,并且如果没有它就不会是类型安全的。我试过了。

尽管在使用 LINQ 时我们发现它很好、很好、很有趣等,但它具有使开发人员变得懒惰的剪切缺点:) 与存储过程相比,它在性能上被证明是糟糕的(可能是最差的)1000 次。

别偷懒了。我正在努力。:)

于 2012-09-25T21:36:30.933 回答
2

对于具有单个数据访问点的简单 CRUD 操作,如果您对语法感到满意,我会说选择 LINQ。对于更复杂的逻辑,如果您擅长 T-SQL 及其更高级的操作,我认为存储过程在性能方面会更高效。您还可以从 Tuning Advisor、SQL Server Profiler、从 SSMS 调试查询等获得帮助。

于 2012-03-10T10:11:39.917 回答
1

结果可以概括为

LinqToSql 用于小型站点和原型。它确实节省了原型设计的时间。

Sps:通用。我可以微调我的查询并始终检查 ActualExecutionPlan / EstimatedExecutionPlan。

于 2011-08-24T04:30:03.467 回答
1
Create PROCEDURE userInfoProcedure
    -- Add the parameters for the stored procedure here
    @FirstName varchar,
    @LastName varchar
AS
BEGIN

    SET NOCOUNT ON;

    -- Insert statements for procedure here
    SELECT FirstName  , LastName,Age from UserInfo where FirstName=@FirstName
    and LastName=@FirstName
END
GO

http://www.totaldotnet.com/Article/ShowArticle121_StoreProcBasic.aspx

于 2011-10-20T17:32:46.473 回答
1

存储过程使测试更容易,您可以在不接触应用程序代码的情况下更改查询。同样对于 linq,获取数据并不意味着它是正确的数据。测试数据的正确性意味着运行应用程序,但使用存储过程很容易测试,而无需接触应用程序。

于 2012-03-06T16:41:50.890 回答
0

LINQ 和 SQL 都有自己的位置。两者都有其缺点和优点。

有时对于复杂的数据检索,您可能需要存储过程。有时您可能希望其他人在 Sql Server Management Studio 中使用您的存储过程。

Linq to Entities 非常适合快速 CRUD 开发。

当然,您可以只使用其中一个来构建应用程序。或者你可以把它混合起来。这一切都取决于您的要求。但是 SQL 存储过程不会很快消失。

于 2011-08-12T15:34:50.857 回答