LINQ-to-SQL vs 存储过程?

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

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

因此,问题是: 对于简单的数据检索,哪种方法更好,LINQ-to-SQL 还是存储进程?有什么特别的优点或缺点吗?

谢谢。

112162 次浏览

Linq 呼叫 Sql。

Sql 服务器将缓存查询计划,因此 sprocs 不会获得性能提升。

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

如果我现在从头开始开发一个新的应用程序,我会使用 Linq,不使用 sprocs。

我猜你是指 Linq To Sql

对于任何 CRUD 命令,很容易分析存储过程的性能和任何技术的性能。在这种情况下,两者之间的任何差别都可以忽略不计。尝试分析超过100,000个 select 查询的5个(简单类型)字段对象,以查明是否存在真正的差异。

另一方面,真正的问题在于您是否愿意将业务逻辑放到数据库中,这是一个反对存储过程的论点。

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

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

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

而且,如果将 Linq 用于更复杂的查询,那么调优数据库将变得更加困难。当存储过程运行缓慢时,DBA 可以完全独立地关注代码,并且有很多选项,这样当他/她完成时仍然可以满足契约。

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

当然,Linq 可以用来调用存储过程。

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

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

  1. 调试我的 DAL 从来没有这么容易过。
  2. 当您的模式发生更改时,编译时间安全性是无价的。
  3. 部署更容易,因为所有内容都被编译成 DLL。不再需要管理部署脚本。
  4. 因为 Linq 可以支持查询任何实现 IQueryable 接口的内容,所以您可以使用相同的语法来查询 XML、 Object 和任何其他数据源,而无需学习新的语法

DBA 没有进行更改的自由 在不强迫您的情况下将数据模型 更改编译后的代码 存储过程,可以隐藏这些 某种程度上的变化,因为 参数列表和结果集 表示的过程返回的 它的合同,和内部可以 改变了,只要 合同仍然有效。

我真的不觉得这有什么好处。能够单独地改变某些东西在理论上可能听起来不错,但是仅仅因为这些改变履行了契约并不意味着它返回了正确的结果。为了能够确定什么是正确的结果,您需要上下文,并且您可以从调用代码获得上下文。

LINQ 相对于 sprocs 的一些优点:

  1. 类型安全 : 我想我们都明白这一点。
  2. 摘要 : 对于 LINQ- 到实体来说尤其如此。这种抽象还允许框架添加额外的改进,您可以很容易地利用这些改进。PLINQ是向 LINQ 添加多线程支持的一个例子。添加此支持所需的代码更改非常少。要编写这种只调用 sprocs 的数据访问代码会困难得多。
  3. 调试支持 : 我可以使用任何。NET 调试器来调试查询。使用 sprocs,您无法轻松调试 SQL,而且这种经验主要与数据库供应商有关(MS SQL Server 提供了查询分析器,但这通常是不够的)。
  4. 供应商无关 : LINQ 可以处理大量数据库,支持的数据库数量只会增加。由于不同的语法或特性支持(如果数据库完全支持 Sprocs) ,Sprocs 并不总是可移植于数据库之间。
  5. Deployment : 其他人已经提到过这一点,但是部署单个程序集比部署一组 sprocs 更容易。这也与第4条联系在一起。
  6. 更简单 : 您不必学习 T-SQL 来进行数据访问,也不必学习调用 sprocs 所必需的数据访问 API (例如 ADO.NET)。这与第三和第四有关。

LINQ vs sprocs 的一些缺点:

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

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

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

我曾经是一个大的 Sproc 家伙,但我开始倾向于 LINQ 作为一个更好的选择一般。如果有一些区域的 sproc 明显更好,那么我可能仍然会编写一个 sproc,但使用 LINQ 访问它。:)

LINQ 并不禁止使用存储过程。我在 LINQ-SQL 和 LINQ-storedproc中使用了混合模式。就个人而言,我很高兴我不用编写存储过程... plow-tu。

LINQ 将使过程缓存膨胀

如果应用程序正在使用 LINQtoSQL,而且查询涉及使用长度可能高度变化的字符串,那么对于每个可能的字符串长度,SQLServer 过程缓存都会因为查询的一个版本而变得臃肿。例如,考虑针对 Person 创建的以下非常简单的查询。AdventureWorks2008数据库中的地址类型表:

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;

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

详情请浏览: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=363290

我认为赞成 LINQ 的论点似乎来自于那些没有数据库开发历史的人(一般来说)。

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

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

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

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

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

不必通过 LINQ 学习 TSQL: 不,你不需要,但是你必须学习 LINQ-这有什么好处呢?

我真的不觉得这有什么好处。能够单独地改变某些东西在理论上可能听起来不错,但是仅仅因为这些改变履行了契约并不意味着它返回了正确的结果。为了能够确定什么是正确的结果,您需要上下文,并且您可以从调用代码获得上下文。

松散耦合的应用程序是所有优秀程序员的终极目标因为它们确实增加了灵活性。能够独立地更改事情是非常棒的,并且正是您的单元测试将确保它仍然返回适当的结果。

在你们不高兴之前,我想 LINQ 有它的位置,有一个美好的未来。但是对于复杂的、数据密集型的应用程序,我认为它还没有准备好取代存储过程。这是我今年在 TechEd 上与一位 MVP 的观点相同的(他们将保持匿名)。

编辑: LINQ to SQL 存储过程方面的东西是我仍然需要阅读更多关于-取决于我发现我可能会改变我的上述抨击;)

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

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

此外,还存在可能的2.0回滚问题。相信我,这种情况在我身上发生过几次,所以我相信其他人也会发生这种情况。

我也同意抽象是最好的。除此之外,ORM 的最初目的是使 RDBMS 与面向对象概念很好地匹配。然而,如果在 LINQ 之前一切都很好,因为必须偏离一点面向对象的概念,那就去他妈的吧。概念和现实并不总是很好地结合在一起。IT 界没有激进分子的容身之地。

LINQ 是一种新的存储方式,它并不是为了取代存储过程而发明的。

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

(1)有人说 LINQ 语句可以在 SQL 服务器中“缓存”,因此不会丢失性能。部分是真的。“ LINQ to SQL”实际上是运行时将 LINQ 语法转换为 TSQL 语句。因此,从性能角度来看,硬编码的 ADO.NETSQL 语句与 LINQ 语句没有什么区别。

(2)举例来说,客户服务用户界面具有“帐户转帐”功能。这个函数本身可能会更新10个 DB 表,并一次性返回一些消息。使用 LINQ,您必须构建一组语句,并将它们作为一个批处理发送到 SQL 服务器。这个转换后的 LINQ-> TSQL 批处理的性能很难与存储过程匹配。理由?因为可以使用内置的 SQL 分析器和执行计划工具调整存储过程中语句的最小单元,所以不能在 LINQ 中这样做。

关键是,当谈论单数据库表和小数据集 CRUD 时,LINQ 和 SP 一样快。但是对于更复杂的逻辑,存储过程的性能更容易调整。

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

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

您可以看到这个简单而体面的代码非常有吸引力。但在引擎盖下面。NET 运行时将其转换为更新批处理。如果只有500行,这就是500行 TSQL 批处理; 如果有100万行,这就是命中。当然,有经验的用户不会使用这种方式来做这项工作,但关键是,这是如此容易落入这种方式。

恕我直言,RAD = LINQ,RUP = 存储处理器。我在一家财富500强的大公司工作了很多年,在很多层次上,包括管理层,坦率地说,我从来不会雇佣 RUP 开发人员来做 RAD 开发。它们是如此孤立,以至于它们对于在流程的其他级别上应该做什么的知识非常有限。对于竖井环境,通过非常特定的入口点让 DBA 控制数据是有意义的,因为其他人坦率地说不知道实现数据管理的最佳方法。

但是大型企业在开发领域的 很痛苦移动缓慢,这是非常昂贵的。有时候你需要更快的移动来节省时间和金钱,LINQ 提供了这一点和更多。

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

根据大师的定义,我将 LINQ 定义为摩托车,将 SP 定义为汽车。 如果你想去一个短途旅行,只有小乘客(在这种情况下2) ,去优雅的 LINQ。 但是,如果你想去旅行,有一个大的乐队,我认为你应该选择 SP. 。

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

希望能有所帮助,我可能错了

LINQ 和 SQL 都有自己的位置,都有自己的缺点和优点。

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

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

当然,你可以只使用其中一种方法来构建应用程序。或者你可以混合一下。这都取决于你的要求。但是 SQL 存储进程不会很快消失。

结果可以概括为

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

通用的。我可以微调我的查询并且总是检查 AccounalExectionPlan/EstimatedExectionPlan。

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

我觉得任何真实的东西你都应该用触发器。

A)使用 linq 编写所有逻辑意味着数据库没有多大用处,因为只有应用程序可以使用它。

B)无论如何,我不相信对象建模比关系建模更好。

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

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

E) Linq to sql 仍然会在您意想不到的时候编写蹩脚的代码。

老实说,我认为 MS 最终将增强 t-sql,以便能够像 linq 那样隐式地执行连接投影。例如,t-sql 应该知道是否要执行 order.lineitems.part。

存储过程使得测试更加容易,您可以在不触及应用程序代码的情况下更改查询。还有 linq,获取数据并不意味着它就是正确的数据。测试数据的正确性意味着运行应用程序,但是使用存储过程,不需要接触应用程序就可以很容易地进行测试。

对于只有一个数据访问点的简单 CRUD 操作,如果您对 LINQ 的语法感到满意,我建议您使用 LINQ。对于更复杂的逻辑,如果您擅长 T-SQL 及其更高级的操作,我认为 sprocs 在性能方面更有效率。您还可以从优化顾问、 SQLServer 事件探查器、从 SSMS 调试查询等方面获得帮助。

所有这些倾向于 LINQ 的答案主要是关于 EASE 的开发,这或多或少与编码质量差或编码懒惰有关。我只是喜欢那样。

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

同样,TypeSafety 提醒“我们小心避免错误的类型转换”,这也是我们通过使用 linq 试图改进的低质量问题。即使在这种情况下,如果数据库中的任何内容发生变化,例如 String 列的大小,那么 linq 也需要重新编译,如果没有重新编译,linq 就不会是类型安全的。.我尽力了。

虽然,我们发现在使用 LINQ 的时候,它是好的、甜蜜的、有趣的等等,但是它有一个明显的缺点,那就是让开发人员变得懒惰:)并且它被证明在性能上比存储处理器差1000倍(可能是最差的)。

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