【问题标题】:Recompile stored procs?重新编译存储过程?
【发布时间】:2009-06-29 20:57:15
【问题描述】:

有没有办法重新编译或至少“检查编译”存储过程?有时我们会进行架构更改——添加或删除一列等。并尽最大努力识别受影响的 procs,只是被我们错过的一个咬住,当它下一次运行时会呕吐。 SQLServer 2k5 或 2k8。

【问题讨论】:

  • 每当您进行架构更改使 SQL 服务器的执行计划无效时,SQL 服务器都会将该 sp 标记为重新编译。你做了什么来关闭它!?
  • 不,比这更严重。 TDD 会帮助我们——例如,这些是依赖于我们删除的列的存储过程,并且在执行过程之前我们不会“发现”它。砰。

标签: sql-server sql-server-2005 sql-server-2008


【解决方案1】:

我将您的问题理解为“当我进行架构更改时,我想验证它们仍然使用新架构正确执行的所有程序”。 IE。如果您删除在过程中的 SELECT 中引用的列,则您希望将其标记为需要更改。因此,具体而言,我不明白您的问题是“我希望在下次执行时重新编译该过程”,因为该工作由引擎为您处理,它将检测与任何架构更改相关的元数据版本更改并丢弃现有的缓存的执行计划。

我的第一个观察是,您在问题中描述的内容通常是 TEST 的工作,您应该在部署过程中有一个 QA 步骤来验证新的“构建”。您可能拥有的最佳解决方案是实施一组最小的单元测试,至少在测试部署中迭代所有存储过程并验证每个的执行 的正确性。这几乎可以消除所有意外情况,至少可以在不利的地方(在生产中或在客户现场)消除它们。

您的下一个最佳选择是依靠您的开发工具来跟踪这些依赖关系。 Visual Studio Database 2008 Database Edition 提供开箱即用的此类功能,它会负责验证您在架构中所做的任何更改。

最后,您的最后一个选择是执行类似于 KM 建议的操作:根据修改后的对象(以及所有依赖于依赖对象的过程,以此类推,以此类推),自动执行迭代。将程序标记为重新编译是不够的,您真正需要的是运行 ALTER PROCEDURE 来触发对其文本的解析和模式的验证(T-SQL 与您常用的语言中的情况有点不同编译/执行周期,“编译”本身仅在过程实际执行时发生)。您可以首先遍历 sys.sql_dependencies 以查找已更改对象的所有依赖项,还可以从 sys.sql_modules 找到依赖项的“模块定义”:

with cte_dep as (
   select object_id
      from sys.sql_dependencies
    where referenced_major_id = object_id('<your altered object name>') 
    union all
    select d.object_id
    from sys.sql_dependencies d
        join cte_dep r on d.referenced_major_id = r.object_id
    )
, cte_distinct as (
    select distinct object_id
        from cte_dep)
select object_name(c.object_id)
    , c.object_id 
    , m.definition
    from cte_distinct c
    join sys.sql_modules m on c.object_id = m.object_id

然后您可以运行依赖的“模块”并重新创建它们(即删除它们并运行“定义”中的代码)。请注意,“模块”比存储过程更通用,还涵盖视图、触发器、函数、规则、默认值和复制过滤器。加密的“模块”将没有可用的定义,为了绝对正确,您还必须考虑在sys.sql_modules 中捕获的各种设置(ansi 空值、模式绑定、作为子句执行等)。

如果您使用动态 SQL,则无法验证。 sys.sql_dependencies 不会捕获它,也不会通过“重新创建”模块进行验证。

总的来说,我认为最好的选择是实施单元测试验证。

【讨论】:

    【解决方案2】:

    如果您在更改表和破坏存储过程时遇到问题,请尝试 sp_depends

    sp_depends [ @objname = ] '<object>' 
    
    <object> ::=
    {
        [ database_name. [ schema_name ] . | schema_name.
            object_name
    }
    

    并在它们破裂之前识别它们。以这种方式使用它:

    EXECUTE sp_depends  YourChangedTableName
    

    另外,您可以使用 sp_recompile

    EXEC sp_recompile YourChangedTable
    

    但这只会标记关联的存储过程,以便在下次运行时重新编译。

    您可以使用管理工作室或源代码管理将所有过程的串联创建脚本生成到单个文件中,然后运行该脚本。

    【讨论】:

    • 这是一个很好的答案,但不幸的是仅适用于同一数据库中的数据库对象。如果来自另一个数据库的某些 sql 代码引用了它,那么 sp_depends 将不会列出该代码。
    【解决方案3】:

    我知道您的意思,并且在许多情况下都可以识别您的需求。你可以看看sp_refreshsqlmodule

    祝你好运,罗恩

    【讨论】:

      【解决方案4】:

      您也许可以使用 DBCC FREEPROCCACHE

      http://msdn.microsoft.com/en-us/library/ms174283.aspx

      【讨论】:

        【解决方案5】:

        sysobjects 获取列表后,只需遍历它们,然后运行sp_recompile

        这是一个显示示例脚本的链接:
        http://database.ittoolbox.com/groups/technical-functional/sql-server-l/recompile-all-stored-procedures-2764478

        【讨论】:

        • 使用“sp_recompile tablename”更容易,因为它将标记重新编译所有引用该表的过程。但是,这不适用于 OP,因为 sp_recompile 仅将过程标记为重新编译。它们实际上是在下次运行时编译的,这与 OP 更改在运行时“呕吐”的时间相同。
        • MSDN 说 sp_recompile “导致存储过程和触发器在下次运行时重新编译。”,因此在 调用 procs 之前不会发现错误
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-21
        • 2013-06-17
        • 2022-11-11
        • 1970-01-01
        相关资源
        最近更新 更多