假设我们在SQL Server重启期间有自动运行的简单日志记录过程:
USE master
GO
CREATE TABLE dbo.silly_logging(id INT IDENTITY(1,1) PRIMARY KEY
,created_date DATETIME DEFAULT GETDATE()
,comment VARCHAR(100));
GO
-- no parametrs
CREATE PROCEDURE dbo.my_procedure
AS
INSERT INTO dbo.silly_logging(comment)
VALUES ('SQL Server Startup');
GO
-- mark procedure to start at SQL Server instance startup
EXEC sp_procoption @ProcName = 'dbo.my_procedure'
, @OptionName = 'startup'
, @OptionValue = 'on';
SELECT name, is_auto_executed
FROM master.sys.procedures
WHERE is_auto_executed = 1;
-- my_procedure 1
-- restart instance
SELECT *
FROM dbo.silly_logging;
--id created_date comment
--1 2017-07-28 07:01:24.650 SQL Server Startup
如果我们尝试使用带参数的程序,我们会收到错误:
CREATE PROCEDURE dbo.my_procedure2 @i INT = 10
AS
SELECT @i;
GO
-- mark procedure to start at SQL Server instance startup
EXEC sp_procoption @ProcName = 'dbo.my_procedure2'
, @OptionName = 'startup'
, @OptionValue = 'on';
消息15399,级别11,状态1,过程sp_procoption,
无法更改启动选项,因为此选项仅限于没有参数的对象。
但我们仍然可以ALTER
现有程序:
ALTER PROCEDURE dbo.my_procedure @text NVARCHAR(100) = 'Default value'
AS
INSERT INTO dbo.silly_logging(comment)
VALUES (@text);
GO
-- restart instance
SELECT *
FROM dbo.silly_logging;
--id created_date comment
--1 2017-07-28 07:01:24.650 SQL Server Startup
--2 2017-07-28 07:03:50.510 Default value
现在我们最终得到了带有参数(默认值)的存储过程。
缺点:无法关闭。
EXEC sp_procoption @ProcName = 'dbo.my_procedure'
, @OptionName = 'startup'
, @OptionValue = 'off';
消息15399,级别11,状态1,过程sp_procoption 无法更改启动选项,因为此选项仅限于没有参数的对象。
当然,如果我使用DROP-CREATE
,一切都会按预期工作。
ExecAtStartup
属性但是CREATE-ALTER
的路径是:
这种工作有什么具体原因吗?具体来说,为什么在更改对象属性(如ExecAtStartup
)时未验证?
答案 0 :(得分:1)
该检查仅在sp_procoption
,因此仅在sp_procoption
执行时进行检查。
ALTER
后仍然运行正常CREATE PROCEDURE dbo.my_procedure
AS
RAISERROR ('fff', 10, 1) WITH LOG
GO
EXEC sp_procoption @ProcName = 'dbo.my_procedure'
, @OptionName = 'startup'
, @OptionValue = 'on';
GO
-- SQL restarted. Check logs
-- Error: 50000 Severity: 10 State: 1 fff
GO
ALTER PROCEDURE dbo.my_procedure
@dummy int = 0
AS
RAISERROR ('ggg', 10, 1) WITH LOG
GO
-- SQL restarted. Check logs
-- Error: 50000 Severity: 10 State: 1 ggg
GO
DROP PROCEDURE dbo.my_procedure
答案 1 :(得分:1)
sp_procoption
显式检查过程是否有效:
在它做任何事之前。
传递这些检查后sp_procoption 'proc', 'startup', 'on'
的唯一影响是将对象属性ExecIsStartup
设置为1
(而off
将其设置为0
)。您可以使用OBJECTPROPERTY
验证这一点。
没有特别原因ALTER PROCEDURE
无法检查此属性并验证过程没有参数并拒绝ALTER
,否则它只是没有。因此,您可以标记启动过程,将其更改为具有参数,然后再遇到sp_procoption
拒绝处理它,即使只是关闭该选项。
如果今天实现了此功能,它可能会获得自己的语法(ALTER PROCEDURE Foo SET STARTUP = ON
)而不是内部存储过程,而Microsoft正在逐渐退出(比较sp_dbcmptlevel
与ALTER DATABASE SET COMPATIBILITY_LEVEL
,sp_attach_db
与CREATE DATABASE FOR ATTACH
)。如果它是ALTER
正确的一部分,那么如果程序标记为ALTER PROCEDURE
,那么STARTUP
也可以检查参数。然而,这是任何人在功能改进的优先级列表中可能并不高的事情之一。
当然,解决方法很简单:如果必须使用(默认)参数作为启动过程调用过程,请从实际上没有参数的包装器存储过程执行此操作并转发调用。因为如果不仔细编写服务器,启动程序可能会使您的服务器崩溃,实际上使用仅进行启动是一个非常好的主意(并使用{{1}给它们命名并且没有让他们在一个带有参数的设置中拉双重任务,因为它很容易在不经意间改变它们。