存储过程与内联 SQL

web*_*ad3 29 performance sql-server stored-procedures query-performance

我知道存储过程通过执行路径更有效(比应用程序中的内联 sql)。然而,当被按下时,我对原因不是很了解。

我想知道对此的技术推理(以稍后我可以向某人解释的方式)。

谁能帮我制定一个好的答案?

Aar*_*and 48

我相信这种观点在某一时刻是正确的,但在当前版本的 SQL Server 中则不然。整个问题在于,过去无法正确优化临时 SQL 语句,因为 SQL Server 只能在批处理级别进行优化/编译。现在我们有了语句级优化,因此来自应用程序的正确参数化查询可以利用与嵌入在存储过程中的查询相同的执行计划。

我仍然更喜欢 DBA 方面的存储过程,原因如下(其中几个可能对性能产生巨大影响):

  • 如果我有多个重复使用相同查询的应用程序,存储过程会封装该逻辑,而不是在不同的代码库中多次乱扔相同的即席查询。重复使用相同查询的应用程序也可能受到计划缓存膨胀的影响,除非它们被逐字复制。即使大小写和空白空间的差异也可能导致存储同一计划的多个版本(浪费)。
  • 我可以检查和排除查询正在做什么,而无需访问应用程序源代码或运行昂贵的跟踪来准确查看应用程序正在做什么。
  • 我还可以控制(并提前知道)应用程序可以运行哪些查询、它可以访问哪些表以及在什么上下文中等等。如果开发人员在他们的应用程序中编写临时查询,他们要么必须每次他们需要使用我不知道或无法预测的桌子时,请拉我的衬衫袖子,或者如果我不那么负责任/热情和/或安全意识,我只是要宣传这一点用户到 dbo,所以他们停止打扰我。通常,这是在开发人员数量超过 DBA 或 DBA 顽固时完成的。最后一点是我们的缺点,我们需要更好地提供您需要的查询。
  • 与此相关的是,一组存储过程是一种非常简单的方法来准确清点可能在我的系统上运行的查询。一旦允许应用程序绕过程序并提交其自己的即席查询,为了找到它们,我必须运行涵盖整个业务周期的跟踪,或解析所有应用程序代码(再次,我可能无法访问)以查找任何看起来像查询的内容。能够查看存储过程列表(并grep 单个源sys.sql_modules,用于对特定对象的引用)使每个人的生活变得更加轻松。
  • 我可以采取更大的措施来防止 SQL 注入;即使我接受输入并使用动态 SQL 执行它,我也可以控制很多允许发生的事情。在构建内联 SQL 语句时,我无法控制开发人员正在做什么。
  • 我可以在无需访问应用程序源代码的情况下优化查询(或多个查询)、进行更改的能力、有效执行此操作的应用程序语言知识、重新编译和重新部署的权限(更不用说麻烦)应用程序等。如果应用程序是分发的,这尤其成问题。
  • 我可以强制存储过程中的某些设置选项,以避免单个查询受到应用程序中某些慢而 SSMS 中某些慢的影响?问题。这意味着对于调用临时查询的两个不同应用程序,一个可以有SET ANSI_WARNINGS ON,另一个可以有SET ANSI_WARNINGS OFF,并且每个应用程序都有自己的计划副本。他们获得的计划取决于使用的参数、适当的统计信息等。在每种情况下第一次调用查询时,这可能会导致不同的计划,从而导致非常不同的性能。
  • 我可以控制数据类型和参数的使用方式,这与某些 ORM 不同 - 某些早期版本的事物(如 EF)会根据参数的长度对查询进行参数化,因此如果我有一个参数 N'Smith' 和另一个 N'约翰逊'我会得到两个不同版本的计划。他们已经解决了这个问题。他们已经解决了这个问题,但还有什么是坏的?
  • 我可以做 ORM 和其他“有用”框架和库尚无法支持的事情。

尽管如此,与技术辩论相比,这个问题可能会引发更多的宗教争论。如果我们看到这种情况发生,我们可能会关闭它。