数据库联机时运行存储过程

问题描述 投票:1回答:2

在Microsoft SQL Server 2012及更高版本中,我想知道当数据库联机时,存储过程是否可以自动执行?我发现this文章展示了如何在服务器实例启动时运行存储过程,但我似乎找不到类似于数据库本身上线的东西。

我需要在数据库联机时运行存储过程,例如,如果数据库是以新名称还原,或者是在备份它的单独服务器/实例上。我想我可以在技术上运行一个定期检查任何新数据库的工作,但数据库可能会恢复到没有安装此工作的服务器上,这有点死路一条。

另一个例子是服务器重新启动,或者数据库因任何原因脱机然后重新联机。从本质上讲,任何时候数据库上线我想通过被解雇的存储过程来了解它。

任何其他建议将不胜感激。

sql-server sql-server-2016
2个回答
1
投票

所以我经历了一切可能的方式,我看着Server Triggers:你可以这样做:

CREATE TRIGGER [TrackDBStarted] 
ON ALL SERVER
FOR CREATE_DATABASE, ALTER_DATABASE

这将在创建数据库时为您提供,但在RESTORED / ATTACHED时则不会为您提供,这样就无法工作。

您可以使用Extended Events,因为它是database_started的事件:

CREATE EVENT SESSION [TrackDBStarted] 
ON SERVER
ADD EVENT sqlserver.database_started
( ACTION ( sqlserver.database_name ) )

但不幸的是你不能Target T-SQL所以这不会起作用。

一种保证的方法是创建一个Startup Procedure,它将允许您创建一个全局Temp Table,它不会超出服务器正常运行时间的范围。从那个Stored Procedure你可以确保创建了一个Agent Job,它将检查每个x时间增量的数据库列表,并对新的Onlined数据库执行操作。这是一段冗长的代码,但它创建/查询/删除所执行的操作,这样任何人都可以从中收集想法。我试图在必要时发表评论,但如果你不理解某些项目,我建议先阅读一下。

如果有人有更好的方法,我会很乐意学习。

创建

USE MASTER;
GO

IF ( OBJECT_ID( N'dbo.STARTUPPROC' ) IS NOT Null )
    DROP PROCEDURE [dbo].[STARTUPPROC];
IF ( OBJECT_ID( N'dbo.CHECKDBS' ) IS NOT Null )
    DROP PROCEDURE [dbo].[CHECKDBS];
GO

/* Create the stored procedure that will check for any new databases. */
CREATE PROCEDURE [dbo].[CHECKDBS]
AS
    SET NOCOUNT ON;

    DECLARE @Database   sysname;

    DECLARE c_databases CURSOR LOCAL FOR    SELECT name FROM sys.databases 
                                            WHERE name NOT IN ( N'master', N'model', N'msdb', N'tempdb' )
                                            AND name NOT IN ( SELECT [Database] FROM ##DBList )
                                            AND state = 0;  -- Online

    OPEN c_databases;
    FETCH NEXT FROM c_databases INTO @Database;

    WHILE ( @@FETCH_STATUS = 0 )
    BEGIN
        IF ( HAS_PERMS_BY_NAME( @Database, 'DATABASE', 'ANY' ) = 1 )  
        BEGIN

            /**************************************
            *** Do database related tasks here. ***
            ***************************************/

            INSERT INTO ##DBList ( [Database] )
            VALUES ( @Database );
        END

        FETCH NEXT FROM c_databases INTO @Database;
    END

    CLOSE c_databases;
    DEALLOCATE c_databases;
GO

/* 
Create the stored procedure that will:
1. Create the temporary table so it doesn't go out of scope. 
2. Create the job that will periodically call the CHECKDBS stored procedure.
*/
CREATE PROCEDURE [dbo].[STARTUPPROC]
AS
    SET NOCOUNT ON;

    -- Create the temporary table if it doesn't already exist.
    IF ( OBJECT_ID( N'tempdb..##DBList' ) IS Null )
    BEGIN
        CREATE TABLE ##DBList
        (
            [Database]  sysname NOT NULL,                       -- Name of the database.
            PRIMARY KEY CLUSTERED 
            (
                [Database] ASC
            )
        );
    END

    DECLARE @JobName    sysname         = N'DBCheck';       -- Name of the job.
    DECLARE @ServerName nvarchar(30)    = @@SERVERNAME;     -- SQL Server on which this job will be configured.
    DECLARE @JobDate    nvarchar(8)     = CONVERT( nvarchar(8), SYSDATETIME(), 112 );   -- Job start date.
    DECLARE @Command    nvarchar(max)   = N'EXEC [dbo].[CHECKDBS]';                     -- The T-SQL command to run in the step.

    -- Check if the job exists and create it if it doesn't.
    IF NOT EXISTS ( SELECT Null FROM msdb.dbo.sysjobs WHERE name = @JobName )
    BEGIN
        -- Add the job.
        EXEC msdb.dbo.sp_add_job 
            @job_name = @JobName;

        -- Add the job step.
        -- See https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-add-jobstep-transact-sql?view=sql-server-2017
        EXEC msdb.dbo.sp_add_jobstep
            @job_name = @JobName,
            @step_name = N'Job Step',
            @subsystem = N'TSQL',
            @command = @Command;

        -- Schedule the job.
        -- See https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-add-jobschedule-transact-sql?view=sql-server-2017
        EXEC msdb.dbo.sp_add_jobschedule @job_name = @JobName,
            @name = N'Minute',                  -- Name of the job schedule.
            @enabled = 1,                       -- Will be enabled.
            @freq_type = 4,                     -- Daily.
            @freq_interval = 1,                 -- Every x days.
            @freq_subday_type = 4,              -- Minutes.
            @freq_subday_interval = 1,          -- Sub day interval.
            @freq_relative_interval = 0,        -- Only used when @freq_type = 32 so set to 0.
            @freq_recurrence_factor = 0,        -- Not used for @freq_type = 4 so set to 0.
            @active_start_date = @JobDate,      -- Date on which job execution should commence, must be greater than or equal to 19900101.
            @active_end_date = 99991231,        -- No end date.
            @active_start_time = 0,             -- Start job at 00:00:00.
            @active_end_time = 235959;          -- End job at 23:59:59.

        -- Add the job to the SQL Server.
        EXEC msdb.dbo.sp_add_jobserver
            @job_name = @JobName,
            @server_name = @ServerName;
    END
GO

/* Mark the stored proc for startup. */
IF ( OBJECT_ID( N'dbo.STARTUPPROC' ) IS NOT Null )
    AND NOT EXISTS ( SELECT Null FROM MASTER.INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = N'STARTUPPROC' AND OBJECTPROPERTY( OBJECT_ID( ROUTINE_NAME ), 'ExecIsStartup' ) = 1 )
    EXEC SP_PROCOPTION N'STARTUPPROC', 'STARTUP', 'ON';
GO

QUERY

USE MASTER;
GO
SELECT * FROM SYS.CONFIGURATIONS WHERE NAME = N'scan for startup procs';
SELECT * FROM MASTER.INFORMATION_SCHEMA.ROUTINES WHERE SPECIFIC_NAME = N'STARTUPPROC' AND OBJECTPROPERTY( OBJECT_ID( ROUTINE_NAME ), 'ExecIsStartup' ) = 1;
SELECT * FROM msdb.dbo.sysjobs WHERE name = N'DBCheck';
SELECT * FROM sys.procedures WHERE name IN ( N'STARTUPPROC', N'CHECKDBS' );
SELECT * from tempdb.sys.objects WHERE name = N'##DBList';
GO

拆除

USE MASTER;
GO

-- Delete the job.
IF EXISTS ( SELECT Null FROM msdb.dbo.sysjobs WHERE name = N'DBCheck' )
    EXEC msdb.dbo.sp_delete_job @job_name = N'DBCheck';
GO

-- Remove the stored procedure and turn off the auto-startup.
IF EXISTS ( SELECT Null FROM MASTER.INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = N'STARTUPPROC' AND OBJECTPROPERTY( OBJECT_ID( ROUTINE_NAME ), 'ExecIsStartup' ) = 1 )
    EXEC SP_PROCOPTION N'STARTUPPROC', 'STARTUP', 'OFF';
GO

-- Drop the stored procedures.
IF ( OBJECT_ID( N'dbo.STARTUPPROC' ) IS NOT Null )
    DROP PROCEDURE [dbo].[STARTUPPROC];
IF ( OBJECT_ID( N'dbo.CHECKDBS' ) IS NOT Null )
    DROP PROCEDURE [dbo].[CHECKDBS];
GO

-- Drop the temporary table.
IF ( OBJECT_ID( N'tempdb..##DBList' ) IS NOT Null )
    DROP TABLE ##DBList;
GO

0
投票

据我了解您的要求,您正在寻找SQL Server实例联机时执行的过程。为此你可以通过下面的文章。

https://www.mssqltips.com/sqlservertip/1574/automatically-running-stored-procedures-at-sql-server-startup/

© www.soinside.com 2019 - 2024. All rights reserved.