DROP … CREATE与ALTER

当涉及到创build存储过程,视图,函数等,最好做一个DROP …对象的CREATE或ALTER?

我已经看到许多“标准”文件说明做一个DROP …创build,但我已经看到许多支持ALTER方法的意见和论据。

ALTER方法保留了安全性,而我听说DROP … CREATE方法在第一次执行时强制重新编译整个SP,而不是仅仅重新编译一个语句级别。

有人可以告诉我,如果有其他的优势/劣势使用之一?

ALTER也会强制重新编译整个程序。 语句级别重新编译适用于程序中的语句,例如。 一个SELECT,因为基础表的改变而重新编译,而不对过程做任何改变。 甚至不可能有select地重新编译ALTER过程中的某些语句,以便了解在ALTER过程之后,SQL文本中发生了什么变化,服务器将不得不…编译它。

对于所有的对象,ALTER总是更好,因为它保留了所有的安全性,所有的扩展属性,所有的依赖和所有的约束。

这是我们的做法:

if object_id('YourSP') is null exec ('create procedure dbo.YourSP as select 1') go alter procedure dbo.YourSP as ... 

该代码创build一个“存根”存储过程,如果它不存在,否则它会做一个改变。 通过这种方式,即使您重复执行脚本,该过程的所有现有权限也都会保留。

改变通常更好。 如果删除并创build,则可能会丢失与该对象关联的权限。

如果你有一个函数/存储过程,例如从一个网站非常频繁地调用,它可能会导致问题。

存储的proc将被丢弃几毫秒/秒,在此期间,所有查询都将失败。

如果你做一个改变,你没有这个问题。

新创build的存储过程的模板通常是这种forms:

 IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = '<name>') BEGIN DROP PROCEDURE <name> END GO CREATE PROCEDURE <name> ...... 

但是,相反,更好的是,

如果存储的proc / function / etc不存在,则使用伪select语句创build它。 然后,改变将永远工作 – 它永远不会被丢弃。

我们有一个存储过程,所以我们的存储过程/函数通常是这样的:

 EXEC Utils.pAssureExistance 'Schema.pStoredProc' GO ALTER PROCECURE Schema.pStoredProc ... 

我们使用相同的存储过程的function:

 EXEC Utils.pAssureExistance 'Schema.fFunction' GO ALTER FUNCTION Schema.fFunction ... 

在Utils.pAssureExistance中,我们做一个IF,看看“。”后的第一个字符:如果是“f”,我们创build一个虚拟函数,如果是“p”,我们创build一个虚拟存储过程。

但要小心,如果您创build了一个虚标量函数,并且您的ALTER位于一个表值函数上,那么ALTER FUNCTION将会失败,表示它不兼容。

同样,Utils.pAssureExistance可以方便的使用附加的可选参数

 EXEC Utils.pAssureExistance 'Schema.fFunction', 'TableValuedFunction' 

将创build一个虚拟表值函数,

另外,我可能是错的,但我认为如果你做一个下拉过程,并且当前正在使用存储过程的查询,它将会失败。

但是,更改过程将等待所有查询停止使用存储的过程,然后进行更改。 如果查询将存储过程“locking”了太长时间(比如说几秒钟),那么ALTER将停止等待locking,并改变存储的过程:使用存储过程的查询可能会失败。

我不知道是否可以做出这样的评论,并说“ALTER更好”。 我想这一切都取决于情况。 如果你需要这种细粒度的权限到过程级别,你可能应该在一个单独的过程中处理这个问题。 有必要删除和重新创build。 它清除了现有的安全性,并将其重置为可预测的。

我一直倾向于使用drop / recreate。 我还发现将它们存储在源代码pipe理中更容易。 而不是做….如果存在做改变,如果不存在做创build。

就这样说…如果你知道你在做什么…我不认为这太重要了。

您已经提出了一个特定的与不包含任何数据的数据库对象相关的问题,理论上不应该经常更改。

可能你可能需要编辑这些对象,但不是每5分钟一次。 正因为如此,我认为你已经击中了头 – 权限。

简短的回答,不是真正的问题,只要权限不是问题

DROP通常会丢失权限和任何扩展属性。

在某些UDF上, ALTER也将失去扩展属性(绝对是在SQL Server 2005多语句表值函数上)。

我通常不会DROPCREATE除非我正在重新创build这些东西(或知道我想失去它们)。

当我们在开发中时,我们曾经使用alter来创build新的function或修改function。 当我们完成我们的开发和testing后,我们会做一个下降和创build。 这修改了特效date/时间戳,以便您可以按date/时间对它们进行sorting。

这也使我们能够看到我们发出的每个交付物的date。

如果存在则更好,因为如果在将脚本移动到QA或testing或生产时有多个环境,则不知道脚本是否已经存在于该环境中。 通过添加一个滴(如果它已经存在),然后添加你将被覆盖,不pipe它是否存在。 然后您必须重新申请权限,但是最好听到您的安装脚本错误。

从SQL Server 2016 SP1开始,现在可以select对存储过程,函数,触发器和视图使用CREATE OR ALTER语法。 请参阅CREATE OR ALTER – SQL Server数据库引擎博客上的SQL Server 2016 SP1中另一个伟大的语言增强function 。 例如:

 CREATE OR ALTER PROCEDURE dbo.MyProc AS BEGIN SELECT * FROM dbo.MyTable END; 

从可用性的angular度来看,下降和创造比改变更好。 在不包含该对象的数据库中,Alter会失败,但是如果有一个IF EXISTS DROP,那么一个CREATE将在一个数据库中工作,该对象已经存在或者在一个数据库中该对象不存在。 在Oracle和PostgreSQL中,通常使用CREATE OR REPLACE创build与SQL SERVER IF EXISTS DROP和CREATE相同的函数和过程。 如果SQL Server拿起这个小而非常方便的语法,那将是很好的。

这是我将如何做到这一点。 将所有这些放在一个给定对象的脚本中。

 IF EXISTS ( SELECT 1 FROM information_schema.routines WHERE routine_schema = 'dbo' AND routine_name = '<PROCNAME' AND routine_type = 'PROCEDURE' ) BEGIN DROP PROCEDURE <PROCNAME> END GO CREATE PROCEDURE <PROCNAME> AS BEGIN END GO GRANT EXECUTE ON <PROCNAME> TO <ROLE> GO