在 C# 源代码或存储过程中保留 SQL 的优点/缺点是什么?我一直在与朋友讨论我们正在开发的一个开源项目(C# ASP.NET 论坛)。目前,大部分数据库访问是通过在 C# 中构建 SQL 内联并调用 SQL Server DB 来完成的。因此,我正在尝试确定对于这个特定项目,哪个是最好的。
到目前为止,我有:
代码中的优点:
- 更易于维护 - 不需要运行 SQL 脚本来更新查询
- 更容易移植到另一个数据库 - 无需移植
存储过程的优点:
- 表现
- 安全
在 C# 源代码或存储过程中保留 SQL 的优点/缺点是什么?我一直在与朋友讨论我们正在开发的一个开源项目(C# ASP.NET 论坛)。目前,大部分数据库访问是通过在 C# 中构建 SQL 内联并调用 SQL Server DB 来完成的。因此,我正在尝试确定对于这个特定项目,哪个是最好的。
到目前为止,我有:
代码中的优点:
存储过程的优点:
我不喜欢存储过程
存储过程更易于维护,因为: * 当您想要更改某些 SQL 时,您不必重新编译您的 C# 应用程序
当数据类型发生变化,或者你想返回一个额外的列,或者其他什么时,你最终都会重新编译它。您可以从应用程序下方“透明”更改 SQL 的次数总体上非常少
- 您最终会重用 SQL 代码。
包括 C# 在内的编程语言都有这个神奇的东西,称为函数。这意味着您可以从多个地方调用相同的代码块!惊人的!然后,您可以将可重用的 SQL 代码放入其中之一,或者如果您想获得真正的高科技,您可以使用为您完成它的库。我相信它们被称为对象关系映射器,并且这些天很常见。
当您尝试构建可维护的应用程序时,代码重复是您可以做的最糟糕的事情!
同意,这就是为什么存储过程是一件坏事。将代码重构和分解(分解成更小的部分)成函数比将 SQL 分解成... SQL 块要容易得多?
你有 4 个网络服务器和一堆使用相同 SQL 代码的 Windows 应用程序现在你意识到 SQl 代码存在一个小问题,所以你宁愿......在一个地方更改 proc 或将代码推送到所有网络服务器,在所有 Windows 框中重新安装所有桌面应用程序(clickonce 可能会有所帮助)
为什么您的 Windows 应用程序直接连接到中央数据库?这似乎是一个巨大的安全漏洞,并且是瓶颈,因为它排除了服务器端缓存。他们不应该通过网络服务或类似于您的网络服务器进行连接吗?
那么,推送 1 个新的存储过程,还是 4 个新的网络服务器?
在这种情况下,推送一个新的存储过程更容易,但根据我的经验,95% 的“推送的更改”会影响代码而不是数据库。如果您当月将 20 件东西推送到网络服务器,将 1 件东西推送到数据库,那么如果您将 21 件东西推送到网络服务器,将零件推送到数据库,您几乎不会损失太多。
更容易进行代码审查。
你能解释一下怎么做吗?我不明白这个。特别是看到存储过程可能不在源代码控制中,因此无法通过基于 Web 的 SCM 浏览器等访问。
Storedprocs 存在于数据库中,在外界看来,它就像一个黑盒子。想要将它们放入源代码控制这样的简单事情会变成一场噩梦。
还有纯粹努力的问题。如果你想向你的 CEO 解释为什么只花费了 700 万美元来建立一些论坛,那么将所有东西分解成一百万层可能是有意义的,但否则为每件小事创建一个存储过程只是额外的笨拙工作。益处。
目前正在这里的其他几个线程上讨论这个问题。我是存储过程的一贯支持者,尽管提出了一些关于 Linq to Sql 的好论据。
在代码中嵌入查询将您与数据模型紧密结合。存储过程是一种良好的契约式编程形式,这意味着 DBA 可以自由更改过程中的数据模型和代码,只要保持由存储过程的输入和输出表示的契约即可。
当查询隐藏在代码中而不是集中在一个易于管理的位置时,调整生产数据库可能会非常困难。
[编辑] 这是另一个当前的讨论
在我看来,你不能在这个问题上投票赞成或反对。这完全取决于您的应用程序的设计。
我完全反对在 3 层环境中使用 SP,在这种环境中你前面有一个应用程序服务器。在这种环境中,您的应用程序服务器可以运行您的业务逻辑。如果您还使用 SP,您将开始在整个系统中分发业务逻辑的实现,并且将变得非常不清楚谁负责什么。最终你会得到一个应用服务器,它基本上只做以下事情:
(Pseudocode)
Function createOrder(Order yourOrder)
Begin
Call SP_createOrder(yourOrder)
End
所以最后你的中间层运行在这个非常酷的 4 服务器集群上,每个集群都配备了 16 个 CPU,它实际上什么都不做!多么浪费!
如果您有一个直接连接到您的数据库或更多应用程序的胖 gui 客户端,那就另当别论了。在这种情况下,SP 可以充当某种伪中间层,将您的应用程序与数据模型分离并提供可控访问。
代码中的优点:
- 更易于维护 - 不需要运行 SQL 脚本来更新查询
- 更容易移植到另一个数据库 - 无需移植
事实上,我认为你有这种倒退。恕我直言,代码中的 SQL 很难维护,因为:
将存储过程视为您从数据库对象调用的方法 - 它们更容易重用,只有一个编辑位置,如果您确实更改了数据库提供程序,更改发生在您的存储过程中,而不是在您的代码中.
也就是说,存储过程的性能提升是最小的,正如 Stu 在我之前所说的那样,你不能在存储过程中设置断点(还)。
CON
我发现在存储过程中进行大量处理会使您的数据库服务器在扩展您的行为时变得单点不灵活。
但是,如果您有多个运行您的代码的服务器,那么在您的程序中而不是在 sql-server 中进行所有这些处理 可能会让您进行更多的扩展。当然,这不适用于仅进行正常获取或更新的存储过程,但适用于执行更多处理(例如循环数据集)的存储过程。
优点
存储过程的性能优势通常可以忽略不计。
存储过程的更多优点:
我落在代码方面。我们构建了所有应用程序(Web 和客户端)都使用的数据访问层,所以从这个角度来看它是 DRY。它简化了数据库部署,因为我们只需要确保表模式是正确的。它简化了代码维护,因为我们不必查看源代码和数据库。
我对与数据模型的紧密耦合没有太大问题,因为我看不出在哪里可以真正打破这种耦合。应用程序及其数据本质上是耦合的。
存储过程。
如果出现错误或逻辑稍有变化,您不必重新编译项目。另外,它允许从不同的来源进行访问,而不仅仅是您在项目中编写查询代码的地方。
我认为维护存储过程并不难,你不应该直接在数据库中编码它们,而是首先在单独的文件中,然后你可以在你需要设置的任何数据库上运行它们。
存储过程的优点:
更容易进行代码审查。
更少的耦合,因此更容易测试。
更容易调整。
从网络流量的角度来看,性能通常更好 - 如果您有游标或类似物,则不会多次访问数据库
您可以更轻松地保护对数据的访问,删除对表的直接访问,通过 procs 加强安全性——这也允许您相对快速地找到更新表的任何代码。
如果涉及其他服务(例如报告服务),您可能会发现将所有逻辑存储在存储过程中比在代码中更容易,并且必须复制它
缺点:
开发人员更难管理:脚本的版本控制:每个人都有自己的数据库,版本控制系统是否与数据库和IDE集成?
在某些情况下,在代码中动态创建的 sql 可以比存储过程具有更好的性能。如果您创建了一个存储过程(例如 sp_customersearch),由于它必须非常灵活,因此它具有数十个参数,因此变得极其复杂,那么您可能可以在运行时在代码中生成一个更简单的 sql 语句。
有人可能会争辩说,这只是将一些处理从 SQL 转移到 Web 服务器,但总的来说这是一件好事。
这种技术的另一个好处是,如果您正在查看 SQL 分析器,您可以看到您生成的查询并对其进行调试,这比看到带有 20 个参数的存储过程调用要容易得多。
我喜欢存储过程,不知道有多少次我能够使用不会对应用程序产生任何停机时间的存储过程对应用程序进行更改。
Transact SQL 的忠实粉丝,调整大型查询已被证明对我非常有用。大约 6 年没有写过任何内联 SQL 了!
您列出了 sprocs 的 2 个优点:
性能 - 不是真的。在 Sql 2000 或更高版本中,查询计划优化非常好,并且被缓存了。我确信Oracle等会做类似的事情。我认为存储过程不再需要性能。
安全?为什么存储过程会更安全?除非您有一个非常不安全的数据库,否则所有访问都将来自您的 DBA 或通过您的应用程序。始终对所有查询进行参数化 - 永远不要从用户输入中内联某些内容,你会没事的。
无论如何,这是性能的最佳实践。
Linq 绝对是我现在进行新项目的方式。看到这个类似的帖子。
@基思
安全?为什么存储过程会更安全?
正如 Komradekatz 所建议的那样,您可以禁止访问表(对于连接到数据库的用户名/密码组合)并仅允许 SP 访问。这样,如果有人获得了您数据库的用户名和密码,他们可以执行 SP,但无法访问表或数据库的任何其他部分。
(当然,执行 sproc 可能会为他们提供所需的所有数据,但这取决于可用的 sproc。授予他们对表的访问权限可以让他们访问所有内容。)
这样想
你有 4 个网络服务器和一堆使用相同 SQL 代码的 Windows 应用程序现在你意识到 SQl 代码存在一个小问题,所以你宁愿......在一个地方更改 proc 或将代码推送到所有网络服务器,在所有 Windows 框中重新安装所有桌面应用程序(clickonce 可能会有所帮助)
我更喜欢存储过程
对 proc 进行性能测试也更容易,将其放入查询分析器 set statistics io/time on set showplan_text on 和瞧
无需运行探查器即可准确查看正在调用的内容
只是我的 2 美分
我更喜欢将它们保存在代码中(使用 ORM,而不是内联或临时),因此它们被源代码控制所覆盖,而无需处理保存 .sql 文件。
此外,存储过程本身并不更安全。您可以使用存储过程编写错误查询,就像内联一样容易。参数化的内联查询可以和存储过程一样安全。
使用您的应用程序代码做它最擅长的事情:处理逻辑。
使用您的数据库做它最擅长的事情:存储数据。
您可以调试存储过程,但您会发现更容易在代码中调试和维护逻辑。通常,每次更改数据库模型时都会结束重新编译代码。
具有可选搜索参数的存储过程也非常无效,因为您必须提前指定所有可能的参数,并且有时无法进行复杂的搜索,因为您无法预测参数将在搜索中重复多少次。
在安全性方面,存储过程更加安全。有些人争辩说,无论如何,所有访问都将通过应用程序进行。许多人忘记的是,大多数安全漏洞都来自公司内部。想想有多少开发人员知道您的应用程序的“隐藏”用户名和密码?
此外,正如 MatthieuF 所指出的,由于应用程序(无论是在桌面服务器还是 Web 服务器上)和数据库服务器之间的往返次数减少,性能可以大大提高。
以我的经验,通过存储过程抽象数据模型也极大地提高了可维护性。作为过去不得不维护许多数据库的人,当面临所需的模型更改时,能够简单地更改一两个存储过程并使更改对所有外部应用程序完全透明,这真是一种解脱。很多时候,您的应用程序并不是唯一指向数据库的应用程序 - 还有其他应用程序、报告解决方案等,因此跟踪所有这些受影响的点可能会成为开放访问表的麻烦。
我还将在加号列中进行检查,以便将 SQL 编程交给专门从事 SQL 编程的人员,并让 SP 更容易隔离和测试/优化代码。
我看到的一个缺点是许多语言不允许传递表参数,因此传递未知数字的数据值可能很烦人,并且某些语言仍然无法处理从单个存储过程中检索多个结果集(尽管后者在这方面不会使 SP 比内联 SQL 更糟)。
我参加的 Microsoft TechEd 安全会议的建议之一是通过存储的过程进行所有调用并拒绝直接访问表。这种方法被称为提供额外的安全性。我不确定仅仅为了安全是否值得,但如果你已经在使用存储过程,它不会受到伤害。
如果你把它放在一个存储过程中,肯定更容易维护。如果涉及的复杂逻辑可能会在未来发生变化,那么当您有多个客户端连接时,将其放入数据库中绝对是一个好主意。例如,我现在正在开发一个具有最终用户 Web 界面和管理桌面应用程序的应用程序,它们都共享一个数据库(显然),并且我试图在数据库上保留尽可能多的逻辑。这是DRY 原则的完美例子。
假设您没有作弊并在存储过程中使用动态 SQL,我坚定地支持存储过程。首先,使用存储过程允许 dba 在存储过程级别而不是表级别设置权限。这不仅对于打击 SQL 注入攻击至关重要,而且对于防止内部人员直接访问数据库和更改内容至关重要。这是一种有助于防止欺诈的方法。除非通过存储程序,否则不应访问包含个人信息(SSN、信用卡号等)或无论如何创建金融交易的数据库。如果您使用任何其他方法,您的数据库就会对公司中的个人开放,以创建虚假的金融交易或窃取可用于身份盗窃的数据。
存储过程也比从应用程序发送的 SQL 更容易维护和性能调整。它们还允许 dba 了解数据库结构更改对数据访问方式的影响。我从未遇到过允许动态访问数据库的优秀 dba。
我们在我现在工作的地方使用存储过程和 Oracle DB。我们也使用 Subversion。所有存储过程都创建为 .pkb 和 .pks 文件并保存在 Subversion 中。我以前做过内联 SQL,这很痛苦!我更喜欢我们在这里做的方式。创建和测试新的存储过程比在代码中进行要容易得多。
有个
较小的原木
另一个未提及的存储过程的小优点:当涉及到 SQL 流量时,基于 sp 的数据访问产生的流量要少得多。当您监控流量以进行分析和分析时,这变得很重要 - 日志将更小且可读性更强。
我不是存储过程的忠实粉丝,但我在一种情况下使用它们:
当查询非常大时,最好将其作为存储过程存储在数据库中,而不是从代码中发送。这样,就不会从应用程序服务器向数据库发送大量字符串字符,而只会"EXEC SPNAME"
发送命令。
当数据库服务器和 Web 服务器不在同一个网络上时(例如,互联网通信),这是多余的。即使不是这样,压力太大也意味着大量带宽的浪费。
但是,伙计,他们管理起来太糟糕了。我尽可能地避开它们。
SQL 存储过程不会提高查询的性能
很明显,使用存储过程比在代码中构建 SQL 有几个优点。
存储过程更易于维护,因为:
当您尝试构建可维护的应用程序时,代码重复是您可以做的最糟糕的事情!
当您发现需要在多个地方更正的逻辑错误时会发生什么?您更容易忘记更改复制和粘贴代码的最后一个位置。
在我看来,性能和安全性的提升是一个额外的优势。您仍然可以编写不安全/低效的 SQL 存储过程。
更容易移植到另一个数据库 - 无需移植
编写所有存储过程以在另一个数据库中创建并不是很困难。事实上 - 它比导出表更容易,因为没有需要担心的主键/外键。
@Terrapin - 存储过程同样容易受到注入攻击。就像我说的:
始终对所有查询进行参数化 - 永远不要从用户输入中内联某些内容,你会没事的。
这适用于存储过程和动态 Sql。
我不确定不重新编译您的应用程序是一个优势。我的意思是,在再次上线之前,您已经针对该代码(应用程序和数据库)运行了单元测试。
@Guy-是的,您是对的,存储过程确实可以让您控制应用程序用户,以便他们只能执行存储过程,而不能执行底层操作。
我的问题是:如果所有通过您的应用程序访问它,使用连接和具有有限更新/插入权限的用户等,这个额外的级别是否会增加安全性或额外的管理?
我的看法是后者。如果他们已经将您的应用程序破坏到可以重写的程度,他们可以使用许多其他攻击。
如果它们动态内联代码,仍然可以对这些 sproc 执行 Sql 注入,因此黄金法则仍然适用,所有用户输入必须始终参数化。
到目前为止我还没有提到过:最了解数据库的人并不总是编写应用程序代码的人。存储过程为数据库人员提供了一种与不太想了解 SQL 的程序员进行交互的方式。大型数据库(尤其是遗留数据库)并不是最容易完全理解的东西,因此程序员可能更喜欢一个简单的界面来满足他们的需求:让 DBA 弄清楚如何连接 17 个表来实现这一点。
话虽如此,用于编写存储过程的语言(PL/SQL 是一个臭名昭著的例子)是相当残酷的。它们通常不提供您在当今流行的命令式、OOP 或函数式语言中看到的任何细节。想想 COBOL。
因此,坚持使用仅抽象出关系细节的存储过程,而不是那些包含业务逻辑的存储过程。
我是 SPROC 代码的忠实支持者。第一个原因是保持代码紧密耦合,其次是易于源代码控制,无需大量自定义实用程序即可将其引入。
在我们的 DAL 中,如果我们有非常复杂的 SQL 语句,我们通常将它们包含为资源文件并根据需要更新它们(这也可以是一个单独的程序集,并且每个 db 换出,等等......)。
这使我们的代码和我们的 sql 调用存储在同一个版本控制中,而不会“忘记”运行一些外部应用程序进行更新。
我一般写OO代码。我怀疑你们中的大多数人可能也会这样做。在这种情况下,对我来说,所有业务逻辑(包括 SQL 查询)都属于类定义似乎很明显。拆分逻辑使其一部分位于对象模型中,一部分位于数据库中,这并不比将业务逻辑放入用户界面中更好。
关于存储过程的安全优势,在较早的答案中已经说了很多。这些分为两大类:
1) 限制对数据的直接访问。这在某些情况下绝对很重要,当您遇到一个时,存储过程几乎是您唯一的选择。然而,根据我的经验,这种情况是例外而不是规则。
2) SQL 注入/参数化查询。这种反对意见是转移注意力。内联 SQL - 甚至是动态生成的内联 SQL - 可以像任何存储过程一样完全参数化,并且可以用任何值得其盐的现代语言轻松完成。这两种方式都没有优势。(“懒惰的开发人员可能不会为使用参数而烦恼”不是一个有效的反对意见。如果您的团队中有开发人员更喜欢将用户数据连接到他们的 SQL 中而不是使用参数,那么您首先尝试教育他们,然后解雇他们如果这不起作用,就像你对有任何其他不良、明显有害习惯的开发人员一样。)
SQL 注入攻击呈上升趋势。有人很容易找到此代码并在您的网站上运行注入攻击。您必须始终参数化您的查询。最好不要在动态 SQL 查询上运行 exec(@x)。IMO,永远使用内联 SQL 并不是一个好主意。
正如一些人所说,存储过程很麻烦,因为它们是另一组与您的代码分开维护的项目。但是它们是可重用的,如果您最终在查询中发现错误,您可以在不重新编译的情况下修复它们。
我想再次投票支持使用存储过程(尽管它们在维护和版本控制方面会带来麻烦)作为限制对基础表的直接访问以提高安全性的一种方式。
当存储过程用于介于应用程序和数据库之间时,它们是最糟糕的。上述使用它们的许多原因都可以通过视图更好地处理。
安全论点是虚假的。它只是将安全问题从应用程序转移到数据库。代码就是代码。我已经看到存储过程从应用程序中获取 SQL 并使用它构建受到 SQL 注入攻击的查询。
一般来说,他们倾向于在所谓的数据库开发人员和所谓的应用程序开发人员之间制造裂痕。实际上,所有编写的代码都是应用程序代码,只是执行上下文的不同。
使用 LINQ、Rails ActiveRecord 或 Hibernate/NHibernate 等丰富的 SQL 生成库可以加快开发速度。在混合中插入存储过程会减慢速度。
我更喜欢使用 O/R 映射器,例如LLBLGen Pro。
它为您提供了相对轻松的数据库可移植性,允许您使用与使用强类型对象的应用程序相同的语言编写数据库访问代码,并且在我看来,它允许您更灵活地处理拉回的数据。
实际上,能够使用强类型对象是使用 O/R 映射器的充分理由。
我对存储过程的投票;作为接近数据的抽象层,对集合有效,可被许多“客户端”(客户端语言)重用。T-SQL 语言有点原始(我猜这是 SO 的大多数 C# 人员都接触过的),但 Oracle 的 PL/SQL 与任何现代编程语言不相上下。
至于版本控制,只需将存储过程代码放在文本文件中进行版本控制,然后运行脚本在数据库中创建过程。
我在其他答案中没有找到的一点是:
如果在您的环境中,数据库及其架构是架构的核心,并且应用程序具有更多的附属角色,那么更多地使用存储过程可能是有意义的,这可能有助于为所有需要访问的应用程序提供一个级别基础数据库,从而减少代码重复(例如,您确定所有访问数据库的应用程序都将始终使用 C# 或其他 .NET 语言编写吗?)。
另一方面,如果应用程序具有更重要的角色,而数据库更多地充当应用程序的后备存储,那么通过提供公共持久层来减少存储过程的使用并减少代码重复可能是明智的,可能基于 ORM 工具/框架。
在这两种情况下,重要的是不要将 DB 视为存储过程的方便存储库。将它们保存在版本控制系统中的源文件中,并尝试尽可能地自动化它们的部署(这实际上对所有与模式相关的工件都有效)。
没有人提到单元测试!
如果你有一个 saveOrder 方法,你可以在里面调用几个方法,并为每个方法创建一个单元测试,但如果你只是调用一个存储过程,就没有办法做到这一点。
我还没有找到一种在源代码控制中轻松维护存储过程的好方法,使其与代码库一样无缝。它只是不会发生。仅这一点就使我将 SQL 放入您的代码中是值得的。在现代系统上,性能差异可以忽略不计。
存储过程的偏好,因为: - 启用在系统运行时修复生产中的一些数据相关问题(这对我来说是第一个) - 数据库和程序之间的干净合同定义(关注点的干净分离) - 更好地移植到不同的数据库供应商(如果写得好,代码更改通常只在 SP 端)。- 更好地进行性能调整
缺点 - 如果 WHERE 子句在使用条件上有很大变化并且需要高性能,则会出现问题。
存储过程的优点 1)。提高了安全性,因为存储过程中的 SQL 本质上是静态的(大多数情况下)。这将防止 SQL 注入。2)。可重用性。如果需要为多个应用程序/组件返回相同的数据,这可能是一个更好的选择,而不是重复 SQL 语句。3)。减少客户端和数据库服务器之间的调用。
我不确定其他数据库,但您可以在大型机上的 db2 中以宿主语言创建存储过程,这使得它们非常强大。
坚定地站在“存储过程对 CRUD/业务逻辑使用不利”阵营。我了解报告、数据导入等方面的需求
程序员希望他们的应用程序中的代码。DBA 想要它在数据库中。
如果两者都有,则可以使用存储过程在两者之间分配工作,程序员不必担心所有这些表如何连接在一起等。(对不起,我知道你想控制一切。) .
我们有一个第 3 方应用程序,它允许在数据库中的视图或存储过程上创建自定义报告。如果我将所有逻辑都放在另一个应用程序的代码中,我将无法重用它。如果您在使用数据库编写所有应用程序的情况下,这不是问题。
存储过程比代码更容易在数据库和源代码控制系统之间失去同步。应用程序代码也可以,但是当您进行持续集成时不太可能。
数据库就是这样,人们不可避免地会对生产数据库进行更改,只是为了暂时摆脱困境。然后忘记在环境和源代码控制系统之间进行同步。生产数据库迟早会成为事实上的记录,而不是源代码控制系统——您会遇到无法删除任何存储过程的情况,因为您不知道它是否正在被使用。
一个好的流程应该只允许通过适当的渠道对生产进行更改,以便您应该能够从源代码控制系统(无数据)从头开始重建数据库。但我只是说因为它可以完成并且确实完成了 - 生产数据库会在紧急时刻进行更改,在大喊大叫的客户的电话之间,经理在你的脖子上喘气等等。
使用存储过程运行临时查询很尴尬 - 使用动态 sql(或 ORM)更容易完成,这可能是我自己使用存储过程的最大缺点。
另一方面,存储过程在您进行更改但不需要重新部署应用程序代码的情况下非常有用。它还允许您在通过网络发送数据之前对其进行整形,其中代码中的 sql 可能必须进行多次调用才能检索而不是整形(尽管现在有一些方法可以运行多个 sql 语句并在单个“调用”中返回多个结果集",就像在 ADO.NET 中的 MARS 中一样),可能会导致更多数据通过您的网络传输。
不过,我不购买有关性能和安全性的任何其他论点。无论是好是坏,都同样受到控制。
您的编程语言和应用程序框架可能是:
如果这两个条件都是两个,则跳过存储过程。
在我工作的地方,sproc 的最大优势是我们可以在时间到来时将更少的代码移植到 VB.NET(来自 VB6)。而且它的代码更少,因为我们对所有查询都使用存储过程。
当我们需要更新查询而不是更新 VB 代码时,它也很有帮助,在所有计算机上重新编译和重新安装它。
对于 Microsoft SQL Server,您应该尽可能使用存储过程来帮助执行计划缓存和重用。为什么要优化计划重用?因为执行计划的生成是相当昂贵的。
尽管在 SQL Server 的后续版本(尤其是 2005 和 2008 年)中,对即席查询的执行计划的缓存和重用有了显着改进,但在处理存储过程时,计划重用问题仍然比即席查询少得多. 例如,如果计划文本完全匹配,SQL 服务器将仅重用执行计划- 一直到注释和空格,例如,如果以下每一行 SQL 要独立执行,则它们都不会使用相同的执行计划:
SELECT MyColumn FROM MyTable WHERE id = @id
select MyColumn from MyTable WHERE id = @id
SELECT MyColumn FROM MyTable WHERE id = @id
SELECT MyColumn FROM MyTable WHERE id = @id -- "some comment"
SELECT MyColumn FROM MyTable WHERE id = @id -- "some other comment"
最重要的是,如果您没有明确指定参数的类型,那么 SQL Server 很可能会出错,例如,如果您使用输入 4 执行上述查询,那么 SQL Server 将参数化使用@id 作为 SMALLINT(或可能是 TINYINT)的查询,因此如果您随后使用 @id 为 4000 执行相同的查询,SQL Server 会将其参数化为 INT,并且不会重用相同的缓存。
我认为还有一些其他问题,老实说,其中大多数可能都可以解决——尤其是在 SQL Server 的更高版本中,但存储过程通常为您提供更多控制。