【问题标题】:Creating stored procedure on the fly. What are the risks/problems?动态创建存储过程。有什么风险/问题?
【发布时间】:2010-09-18 17:35:49
【问题描述】:

我正在考虑动态创建存储过程。

即在(Web)应用程序运行时运行 CREATE PROCEDURE...。

它可能导致什么风险或问题?

  • 我知道数据库帐户需要有额外的权限。
  • 它不会每天都发生。只是偶尔。
  • 我正在使用 sql server,并且对 mysql 和 postgres 也很感兴趣。

更新1:

感谢 cmets,我正在考虑创建一个新版本的存储过程并切换而不是 ALTERing sp。例如:sp1 -> sp2 -> sp3

更新2:

原因:

我的架构因自定义字段而改变(未知的列数和类型) 我首先尝试了动态 sql 和 sp_executesql。当然可以。动态 sql 适用于 1,2,3 简单更新、插入。

但是它变得太丑了,工作量很大,并且不能很好地与存储过程混合,sql参数化问题,因为它在存储过程中使用并且参数的数量和类型在编译时是未知的(长故事)。

至少这个解决方案的基本场景没有那么复杂。 sp 的逻辑不会改变。对于每个自定义字段,我必须向 sp 添加一个新参数并添加一个列来更新、插入等。

我还考虑过使存储过程参数动态化,例如 sp_executesql,它接受任意数量和类型的参数,但找不到方法。

【问题讨论】:

  • 如果您不介意我问,您能否详细说明您考虑此选项的一些“充分理由”?
  • 架构因自定义字段而发生变化。我可以使用动态 sql,但缺点是性能问题,它使其他事情变得困难。动态 sql 在简单的情况下运行良好,但不适用于(有点复杂的)存储过程。有很多细节...

标签: sql sql-server tsql stored-procedures


【解决方案1】:

对于事务系统,它可能相当昂贵。如果你有一个大批量的工作,并且出于某种原因想要使用代码生成器(ETL 工具中相当常见的架构,特别是 Oracle Warehouse BuilderWherescape Red),那么这样做并不是不合理的。

【讨论】:

    【解决方案2】:

    您提到在执行此更改时将添加和/或更改存储过程的调用配置文件。您如何使用调用它的应用程序锁定新的调用配置文件?如果您必须恢复所做的更改,您的回滚计划是什么?

    过去我所做的只是将递增的数字后缀附加到具有新调用配置文件的存储过程名称 - 然后您可以修改旧版本的 SP 以使用默认值调用新版本参数,然后你可以发布你的软件调用新版本。

    如果您的新版本出现问题并且您必须回滚,则对旧存储过程的调用仍将正常工作,并且只需使用您的默认值填充自定义字段。

    【讨论】:

      【解决方案3】:

      首先,这个问题的答案实际上取决于这个存储过程到底打算做什么。如果它只是读取数据或创建用于报告的结果集,并且您不介意它是否有点不一致,那么您可能没问题。如果它对您的数据做任何有趣的事情,那么这是一件非常冒险的事情。您应该考虑两个用户用户(或同一用户两次)是否有可能(以及会发生什么)同时运行同一存储过程的多个版本。我闻起来像火车残骸。一种选择是只允许在没有其他用户登录系统时进行此过程更改,或者如果他们登录,则强制将它们从数据库中引导。另一种选择是创建一个名称稍有不同的新存储过程,并在您认为这样做安全时交换它们。

      【讨论】:

      • 逻辑没有改变。只有列被添加到更新、插入中。简单来说就是用new sp代替动态sql。我不知道是否可以同时运行两个版本的 sp,但如果发生它不会有问题。这就像运行动态 sql 的变体(具有不同的列)
      【解决方案4】:

      另一个问题是存储过程的主要好处之一是执行计划被缓存,这意味着它将执行得更快。如果您在运行中创建它们,您将失去该优势。

      【讨论】:

      • 我提到它不会每天都发生。只是偶尔一次
      • 啊,你做到了。我必须承认我在喝咖啡之前阅读并回答了这个问题!
      • all sql 的执行计划被缓存,所以从这个角度来看,SP 并没有真正提供任何优势
      • 我不会再将此归类为存储过程的主要优势,至少在 SQL Server 中是这样。
      【解决方案5】:

      如果你真的需要这样做,那么你应该随机化程序的名称以避免与其他用户发生冲突。永远记住,其他用户可能同时在做他们自己的事情——大多数数据库系统不会为存储过程提供事务隔离(我知道只有 Postgres 这样做)。

      这将是一件令人向往的事情,这是极其罕见的——您能否详细说明是什么让您选择了这种方法?

      【讨论】:

        【解决方案6】:

        我不会亲自这样做。

        正如您所提到的,您需要额外的权限才能授予创建/更改数据库对象的访问权限。这可能会造成严重的安全风险,因为如果有人发现其中存在安全漏洞,没有什么能阻止您的应用程序创建恶意存储过程。

        如果您的架构发生更改,请使用该架构更改存储过程。

        【讨论】:

        • 当用户添加自定义字段时,架构会在运行时发生变化
        【解决方案7】:

        如果一个或多个用户正在运行该过程,或者另一个引用您的过程的过程,您将无法更改该过程。您将阻塞,直到所有相关过程和要编译的过程(我认为您从过程中调用的过程,但我不确定)都没有使用。在繁忙的生产系统上,这可能需要很长时间,如果运气不好,您可能会超时等待所有依赖项都未使用(Oracle 上为 5 分钟)。
        你也可能陷入非常丑陋的境地(我有)。以存储过程 B 和 C 为例,它们都调用 A,即您尝试编译的过程。当没有人运行 B 时,系统会锁定 B。现在任何试图运行 B 的用户都会停止。然后系统尝试锁定 C,但 C 正在生成一个非常长的报告,该报告将在另外 10 分钟内完成。您将超时等待锁定,并且您的一些用户将有 5 分钟无响应的系统。我的经验是使用 Oracle,我会确保您的目标 DBMS 不会以相同的方式运行,或者具有更快的故障或更好的锁定获取策略。
        我想我是在警告说,在开发服务器上看起来可能工作的东西在繁忙的生产系统上可能会严重失败。

        【讨论】:

          【解决方案8】:

          我不确定 Tony BanBrahim 讨论的锁定在 SQL Server 2005 中是否正确。

          我有一些长时间运行的 SP(大约 30 个子进程的 3 小时批处理),并且我能够在 SP 仍在运行时对其进行更改。 (我不相信更改在下一次运行之前生效,但它不会导致任何阻塞或任何错误)。现在,外部长时间运行的 SP 既可以使用 EXEC 动态调用 SP,也可以静态调用 SP,但是我已经更改了根 SP 和嵌套 SP,它们在没有错误消息或块的情况下运行。

          WRT 你最初的问题,我认为如果以受控方式使用你的策略是可以的。

          【讨论】:

            【解决方案9】:

            我不确定,但听起来像是一个或两个:

            • 架构问题
            • 现有代码是否从应用程序锁定架构表?

            我会看一下锁定模式表的代码并重写该代码。您是否有第 3 方在锁定这些表?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-07-18
              相关资源
              最近更新 更多