在创建存储过程,视图,函数等时,最好是在对象上执行DROP ... CREATE或ALTER吗?
我已经看过很多“标准”文档,声明要做DROP ... CREATE,但我看到很多评论和论据都主张ALTER方法。
ALTER方法保留了安全性,而我听说DROP ... CREATE方法在第一次执行时强制重新编译整个SP,而不仅仅是重新编译语句级别。
有人可以告诉我,使用其中一个是否有其他优点/缺点?
答案 0 :(得分:51)
我们就是这样做的:
if object_id('YourSP') is null
exec ('create procedure dbo.YourSP as select 1')
go
alter procedure dbo.YourSP
as
...
如果代码尚不存在,代码会创建一个“存根”存储过程,否则会进行更改。这样,即使重复执行脚本,也会保留对过程的任何现有权限。
答案 1 :(得分:46)
ALTER也会强制重新编译整个过程。语句级别重新编译适用于过程内的语句,例如。单个SELECT,由于基础表发生更改而重新编译,没有对过程进行任何更改。甚至不可能有选择地重新编译ALTER过程中的某些语句,以便在服务器必须编译ALTER过程之后理解在SQL文本中改变了什么。< / p>
对于所有对象,ALTER总是更好,因为它保留了所有安全性,所有扩展属性,所有依赖性和所有约束。
答案 2 :(得分:8)
改变通常会更好。如果删除并创建,则可能会丢失与该对象关联的权限。
答案 3 :(得分:2)
从SQL Server 2016 SP1开始,您现在可以选择对存储过程,函数,触发器和视图使用CREATE OR ALTER
语法。请参阅SQL Server数据库引擎博客上的CREATE OR ALTER – another great language enhancement in SQL Server 2016 SP1。例如:
CREATE OR ALTER PROCEDURE dbo.MyProc
AS
BEGIN
SELECT * FROM dbo.MyTable
END;
答案 4 :(得分:1)
如果你有一个从网站上频繁调用的函数/存储过程,它可能会导致问题。
存储过程将被删除几毫秒/秒,在此期间,所有查询都将失败。
如果您进行了更改,则不会出现此问题。
新创建的存储过程的模板通常是以下形式:
IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = '<name>')
BEGIN
DROP PROCEDURE <name>
END
GO
CREATE PROCEDURE <name>
......
然而,相反的是更好的,imo:
如果storedproc / function / etc不存在,请使用虚拟select语句创建它。然后,alter将始终有效 - 它永远不会丢弃。
我们有一个存储过程,所以我们的存储过程/函数通常是这样的:
EXEC Utils.pAssureExistance 'Schema.pStoredProc'
GO
ALTER PROCECURE Schema.pStoredProc
...
我们对函数使用相同的存储过程:
EXEC Utils.pAssureExistance 'Schema.fFunction'
GO
ALTER FUNCTION Schema.fFunction
...
在Utils.pAssureExistance中我们做一个IF并查看“。”之后的第一个字符:如果它是“f”,我们创建一个虚拟函数,如果它是“p”,我们创建一个虚拟存储过程。 / p>
但要注意,如果你创建一个虚拟标量函数,并且你的ALTER是一个表值函数,那么ALTER FUNCTION会失败,说它不兼容。
同样,Utils.pAssureExistance可以很方便,还有一个额外的可选参数
EXEC Utils.pAssureExistance 'Schema.fFunction', 'TableValuedFunction'
将创建一个虚拟表值函数,
另外,我可能错了,但我认为如果你执行了drop过程并且查询当前正在使用存储过程,那么它将会失败。
但是,alter procedure将等待所有查询停止使用存储过程,然后更改它。如果查询“锁定”存储过程太长时间(比如几秒钟),则ALTER将停止等待锁定,并且无论如何都会改变存储过程:使用存储过程的查询可能会在此时失败。 / p>
答案 5 :(得分:1)
我不知道是否有可能做出这样的一揽子评论并说“ALTER更好”。我认为这一切都取决于具体情况。如果您需要这种精细的权限,直到程序级别,您可能应该在单独的过程中处理此问题。不得不放弃和重新创建有好处。它清除现有的安全性并将其重置为可预测的。
我总是喜欢使用drop / recreate。我还发现将它们存储在源代码控制中更容易。而不是......如果存在,则确实改变,如果不存在,则创建。
话虽如此......如果你知道你在做什么......我认为这不重要。
答案 6 :(得分:0)
您已经提出了一个专门针对不包含任何数据的DB对象的问题,理论上不应该经常更改。
您可能需要编辑这些对象,但不是每5分钟编辑一次。因此,我认为你已经击中了头部 - 权限。
简短回答,不是真正的问题,只要权限不是问题
答案 7 :(得分:0)
DROP
通常会失去权限和任何扩展属性。
在某些UDF上,ALTER
也将丢失扩展属性(当然在SQL Server 2005多语句表值函数上)。
我通常不会DROP
和CREATE
,除非我也在重新制作这些东西(或者知道我想丢失它们)。
答案 8 :(得分:0)
我们曾经在开发工作中使用alter创建新功能或修改功能。当我们完成开发和测试后,我们会做一个下降并创建。这会修改触发器上的日期/时间戳,以便您按日期/时间对它们进行排序。
它还使我们能够看到我们发出的每个可交付成果的日期是什么样的。
答案 9 :(得分:0)
使用drop添加如果存在更好,因为如果在将脚本移动到QA或测试或生成时有多个环境,则不知道该脚本是否已存在于该环境中。通过添加一个drop(如果它已经存在)然后添加你将被覆盖,无论它是否存在。然后,您必须重新申请权限,但最好还是听错了安装脚本。
答案 10 :(得分:0)
如果执行 DROP ,然后使用 CREATE ,则几乎可以 与使用 ALTER VIEW 语句的效果相同。问题是您需要重新建立对谁可以使用和不能使用该视图的权限。 ALTER 保留所有依赖项信息并设置权限。
答案 11 :(得分:-1)
从可用性的角度来看,drop和create比alter更好。更改将在不包含该对象的数据库中失败,但具有IF EXISTS DROP,然后CREATE将在具有该对象的数据库中或在该对象不存在的数据库中工作。在Oracle和PostgreSQL中,通常使用CREATE OR REPLACE语句创建函数和过程,该语句与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