当前位置:  开发笔记 > 编程语言 > 正文

编写sql存储过程的最佳实践是什么?

如何解决《编写sql存储过程的最佳实践是什么?》经验,为你挑选了4个好方法。

我发现SQL存储过程非常有趣和有用.我已经编写了存储过程,但我想为任何类型的要求编写精心设计,性能良好的调优和简洁的SP,并且也希望了解存储过程的任何技巧或良好实践.如何在编写存储过程时从初学者升级到高级阶段?

更新:从评论中发现我的问题应该更加具体.每个人都有一些技巧,我期待他们在他们的代码中使用SP的技巧和做法,使他们与其他人区别开来,更重要的是提高写作和使用存储过程的工作效率.



1> RoadWarrior..:

这是我的存储过程错误处理指南.

使用其完全限定名称调用每个存储过程以提高性能:即服务器名称,数据库名称,架构(所有者)名称和过程名称.

在创建每个存储过程的脚本中,显式指定允许执行过程的角色,例如public或者其他.

使用sysmessage,sp_addmessage和占位符而不是硬编码的错误消息.

使用sp_addmessage和sysmessages时,请始终使用错误消息编号50001或更高版本.

使用RAISERROR时,始终为警告消息提供<= 10的严重性级别.

使用RAISERROR时,始终为错误消息提供11到16之间的严重性级别.

请记住,使用RAISERROR并不总是中止正在进行的任何批处理,即使在触发器上下文中也是如此.

在使用或查询之前将@@ error错误保存到局部变量.

在使用或查询之前,将@@ rowcount保存到本地变量.

对于存储过程,请使用返回值仅指示成功/失败,而不是任何其他/额外信息.

存储过程的返回值应设置为0表示成功,非零表示失败.

将ANSI_WARNINGS设置为ON - 这将检测任何聚合分配中的空值,以及超出字符或二进制列的最大长度的任何分配.

设置NOCOUNT ON,原因有很多.

仔细考虑是否要XACT_ABORT ON或OFF.无论你走哪条路,都要保持一致.

退出第一个错误 - 这实现了KISS模型.

执行存储过程时,请始终检查@@ error和返回值.例如:

EXEC @err = AnyStoredProc @value
SET  @save_error = @@error
-- NULLIF says that if @err is 0, this is the same as null
-- COALESCE returns the first non-null value in its arguments
SELECT @err = COALESCE( NULLIF(@err, 0), @save_error )
IF @err <> 0 BEGIN 
    -- Because stored proc may have started a tran it didn't commit
    ROLLBACK TRANSACTION 
    RETURN @err 
END

执行导致错误的本地存储过程时,请执行回滚,因为该过程可能已启动它未提交或回滚的事务.

不要以为只是因为你没有启动一个事务,没有任何活动的事务 - 调用者可能已经启动了一个事务.

理想情况下,避免在调用者启动的事务上进行回滚 - 因此请检查@@ trancount.

但是在触发器中,总是进行回滚,因为您不知道调用者是否发起了活动事务(因为@@ trancount总是> = 1).

在以下声明后始终存储并检查@@ error:

INSERT, DELETE, UPDATE
SELECT INTO
Invocation of stored procedures
invocation of dynamic SQL
COMMIT TRANSACTION
DECLARE and OPEN CURSOR
FETCH from cursor
WRITETEXT and UPDATETEXT

如果DECLARE CURSOR在进程全局游标(缺省值)上失败,则发出语句以释放游标.

小心UDF中的错误.当UDF中发生错误时,函数的执行会立即中止,调用UDF的查询也会中止 - 但@@错误为0!在这些情况下,您可能希望使用SET XACT_ABORT ON运行.

如果要使用动态SQL,请尝试在每个批处理中只有一个SELECT,因为@@ error仅保存最后执行的命令的状态.一批动态SQL中最可能出现的错误是语法错误,SET XACT_ABORT ON不会处理这些错误.



2> Cade Roux..:

我总是尝试使用的唯一技巧是:始终在顶部附近的注释中包含示例用法.这对于测试SP也很有用.我喜欢包含最常见的示例 - 然后您甚至不需要SQL Prompt或单独的.sql文件与您最喜欢的调用,因为它存储在服务器中(如果您有存储的procs查看,这是特别有用的sp_who输出块或其他什么,并采取一堆参数).

就像是:

/*
    Usage:
    EXEC usp_ThisProc @Param1 = 1, @Param2 = 2
*/

然后,要测试或运行SP,只需在脚本中突出显示该部分并执行即可.



3> AR...:

这是一个非常普遍的问题,但这里有几条建议:

一致地命名存储过程.许多人使用前缀来标识它是一个存储过程,但不要使用'sp_'作为为主数据库指定的前缀(无论如何在SQL Server中)

设置NOCOUNT,因为这会减少可能的返回值的数量

基于集合的查询通常比游标执行得更好.这个问题更加详细.

如果您为存储过程声明了变量,请使用良好的命名约定,就像在任何其他类型的编程中一样.

使用其完全限定名称调用SP以消除应该调用哪个SP的混淆,并帮助提高SQL Server性能; 这样可以更容易地找到有问题的SP.

当然还有更多.以下是更多链接: SQL Server存储过程优化提示



4> Simon Hughes..:

    始终使用SET NOCOUNT ON

    如果要执行两次或更多次插入/更新/删除,请使用事务.

    永远不要命名你的过程'sp_'.SQL Server将首先查看master数据库,而不是找到它,然后再查看数据库.如果以不同的方式命名proc,SQL Server将首先查看您的数据库.

坏:

SET NOCOUNT ON
BEGIN TRAN
  INSERT...
  UPDATE...
COMMIT

更好,但看起来凌乱,代码的主要痛苦:

SET NOCOUNT ON
BEGIN TRAN
  INSERT...
  IF @ErrorVar <> 0
  BEGIN
      RAISERROR(N'Message', 16, 1)
      GOTO QuitWithRollback
  END

  UPDATE...
  IF @ErrorVar <> 0
  BEGIN
      RAISERROR(N'Message', 16, 1)
      GOTO QuitWithRollback
  END

  EXECUTE @ReturnCode = some_proc @some_param = 123
  IF (@@ERROR <> 0 OR @ReturnCode <> 0)
       GOTO QuitWithRollback 
COMMIT
GOTO   EndSave              
QuitWithRollback:
    IF (@@TRANCOUNT > 0)
        ROLLBACK TRANSACTION 
EndSave:

好:

SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRY
    BEGIN TRAN
    INSERT...
    UPDATE...
    COMMIT
END TRY
BEGIN CATCH
    IF (XACT_STATE()) <> 0
        ROLLBACK
END CATCH

最好:

SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
    INSERT...
    UPDATE...
COMMIT

那么"最佳"解决方案的错误处理在哪里?你不需要任何.请参阅SET XACT_ABORT ON,这意味着如果有任何错误,请执行自动回滚.代码更清晰,更易于阅读,更易于编写,并且减少了错误.由于SQL Server现在为您执行此操作,因此不会错过任何错误.

推荐阅读
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有