SQL Server 2012 AlwaysOn 2ノードサーバーをインストールし、新しい "イントラネット"用に構成しました。私はAlwaysOnをうまく機能させており、イントラネット用のフロントエンドサーバーはSharePoint 2013を使用します。グリッチは、SharePoint 2013がデータベースをSQL Server 2012バックエンドに自動的に追加するように構成されていますが、AlwaysOnにはありません。これについて読んだり、Microsoft MSDNサポートに連絡したりする際のデフォルトの答えは、「手動で検索、選択、バックアップしてから、AlwaysOnにそれらの新しいデータベースを個別に追加する必要がある」です。
ちょっと待って;これはかなりの作業になる可能性があり、SQL Serverバックエンドサーバーを常にチェックして、作成されたデータベースを確認し、それらをAlwaysOn 7/24に追加する必要があります。新しいデータベースをチェックし、それらの新しいデータベースをフルモードでバックアップし(もちろん、AlwaysOnに追加するため)、それらのデータベースをAlwaysOnにすべて自動的に追加するスクリプトまたはプロセスを探しています。または、これを... 1〜2時間ごとに実行しますか? (ユーザーの介入なし)
これまでに思いついたのは、新しく追加されたデータベースを実際に識別し(まだAlwaysOnにはない)、このスクリプトを共有場所にバックアップするスクリプトです。私の次のタスクは、新しく追加されたデータベースを見つけ、必要なさまざまなプロセスを介してそれらをAlwaysOnに追加することです。これには、ある種のループ動作が含まれると思います。私はT-SQL /スクリプト作成の第一人者ではありません。これを実行するためにアクセスする可能性のあるソリューションまたはスクリプトはありますか? (データベースをAlwaysOnに自動的に追加)?
私にこの問題が発生した最初の人ではないことを確信してください。これまでにさまざまなインターネットサイト(これを含む)で投稿を確認しましたが、解決策が間違っているか、「確認して、先に進めて、スクリプトを作成してください!」のようなメッセージが表示されます。ありがとう。でも、もう少し詳細が必要です。
再度、感謝します、
-アレン
DECLARE @name VARCHAR(50) -- database name
DECLARE @path VARCHAR(256) -- path for backup files
DECLARE @fileName VARCHAR(256) -- filename for backup
-- specify database backup directory
SET @path = '\\atel-web-be2\backups\'
DECLARE db_cursor CURSOR FOR
select name from sys.databases
where group_database_id is null and replica_id is null
and name not in('master','model','msdb','tempdb')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fileName = @path + @name + '.BAK'
BACKUP DATABASE @name TO DISK = @fileName
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
作成された新しいデータベースをチェックし、それを実行するようにスケジュールするためにカーソルtsqlスクリプトを記述する必要はありません。毎分。代わりに、EVENTDATA()関数をサーバーレベルのトリガーと組み合わせて使用します。
IF EXISTS (SELECT * FROM sys.server_triggers
WHERE name = 'ddl_trig_database')
DROP TRIGGER ddl_trig_database
ON ALL SERVER;
GO
CREATE TRIGGER ddl_trig_database
ON ALL SERVER
FOR CREATE_DATABASE
AS
PRINT 'Database Created.'
SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
GO
DROP TRIGGER ddl_trig_database
ON ALL SERVER;
GO
これで、新しいデータベースが作成されたときに起動する自動化メカニズムが準備できたので、 ALTER AVAILABILITY GROUP および ALTER DATABASE-SET HADR を使用できます。
基本的にあなたは単に含める必要があります:
-- Move each database into the Availability Group
-- Change database name and Group as per your environment.
ALTER DATABASE Test1 SET HADR AVAILABILITY GROUP = TestAG
ALTER DATABASE Test2 SET HADR AVAILABILITY GROUP = TestAG
GO
これをもう少し考えると、より創造的に自動化できます-
-- create a driver table
create table AlwaysON_Candidates (
DatabaseName sysname
,createdate datetime default getdate()
,IsAlwaysOnMember bit default 0 -- 0 = Not a part of AG
) -- 1 = Is part of AG
go
-- below insert will be governed by the server level trigger
insert into AlwaysON_Candidates (DatabaseName)
values ('Test1')
--- check the values in the driver table
select *
from AlwaysON_Candidates
--- add database to AG
alter database Test1
set HADR AVAILABILITY group = TestAG
-- update the bit in the driver table AlwaysON_Candidates
update AlwaysON_Candidates
set IsAlwaysOnMember = 1
where DatabaseName = 'Test1'
tsqlを使用して設定するためのいくつかの優れたリファレンスが見つかります here および here
EDIT:以下のスクリプトが役立ちます。明らかに、それを理解し、テスト環境でテストする必要があります。
/************************************************************************************
Author : Kin Shah
Version : 1.0.0 for dba.stackexchange.com
Note: This script does not have ERROR handling and is not tested.
Use at your own risk, It will print out the sql statements, but wont execute it
unless the print statements have been modified to use "exec"
UNDERSTAND the script and then test it on a TEST environment !!!!!!!!
*************************************************************************************/
-- create table
set ansi_nulls on
go
set quoted_identifier on
go
create table AlwaysON_Candidates (
ID int identity(1, 1)
,EventType nvarchar(128) null
,DatabaseName nvarchar(128) null
,LoginName nvarchar(128) null
,UserName nvarchar(128) null
,AuditDateTime datetime null
,IsAlwaysOnMember bit default 0
)
go
alter table [dbo].[AlwaysON_Candidates] add default((0))
for [IsAlwaysOnMember]
go
-- create server trigger
if exists (
select *
from master.sys.server_triggers
where parent_class_desc = 'SERVER'
and name = N'ddl_trig_database'
)
drop trigger [ddl_trig_database] on all server
go
set ansi_nulls on
go
set quoted_identifier on
go
create trigger [ddl_trig_database] on all server
for CREATE_DATABASE as
insert into NewDatabases
select EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(128)') as EventType
,EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]', 'nvarchar(128)') as DatabaseName
,EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]', 'nvarchar(128)') as LoginName
,EVENTDATA().value('(/EVENT_INSTANCE/UserName)[1]', 'nvarchar(128)') as UserName
,GETDATE() as AuditDateTime
,0 as IsAlwaysOnMember
go
set ansi_nulls off
go
set quoted_identifier off
go
ENABLE trigger [ddl_trig_database] on all server
go
--- PREREQUISITE ... CREATE A LINKED SERVER FROM PRIMARY TO SECONDARY SERVER !!!
--- fill in *** CHANGE HERE values
--- test it on a TEST server
--- Not tested and not responsible for any dataloss. UNDERSTAND it and test it before implementing it.
declare @databasename varchar(max)
declare @sqlbackup varchar(max)
declare @sqlrestore varchar(max)
declare @PrimaryAG varchar(max)
declare @SecondaryAG varchar(max)
declare @backupPath varchar(max)
set @backupPath = '\\servername\sharedfolder\' --- *** CHANGE HERE
declare @group sysname
set @group = N'your_group_name' --- *** CHANGE HERE
declare @remotesql1 varchar(max)
declare @remotesql2 varchar(max)
declare @linkedserverName sysname
set @linkedserverName = 'kin_test_AG_LS' --- *** CHANGE HERE
select @databasename = min(DatabaseName)
from AlwaysON_Candidates
where IsAlwaysOnMember = 0
while @databasename is not null
begin
-- ** BACKUP HAPPENS HERE **
select @sqlbackup = N'BACKUP DATABASE ' + QUOTENAME(@databasename) + ' TO DISK = ''' + @backupPath + @databasename + '_forAG.BAK'' WITH COPY_ONLY, FORMAT, INIT, COMPRESSION;
BACKUP LOG ' + QUOTENAME(@databasename) + ' TO DISK = ''' + @backupPath + @databasename + '_forAG.TRN'' WITH INIT, COMPRESSION;'
from AlwaysON_Candidates
where IsAlwaysOnMember = 0
print @sqlbackup --- *** CHANGE HERE for EXEC master..sp_executesql @sqltext
-- ** RESTORE HAPPENS HERE **
select @sqlrestore = N'RESTORE DATABASE ' + QUOTENAME(@databasename) + ' FROM DISK = ''' + @backupPath + @databasename + '_forAG.BAK'' WITH REPLACE, NORECOVERY;
RESTORE LOG ''' + @backupPath + @databasename + '_forAG.TRN'' WITH NORECOVERY;'
print @sqlrestore
select @remotesql1 = N'EXEC ' + QUOTENAME(@linkedserverName) + '.master..sp_executesql @sqlrestore;'
print @remotesql1 --- *** CHANGE HERE for EXEC master..sp_executesql @sqltext
-- join the AG group on primary
select @PrimaryAG = N'ALTER AVAILABILITY GROUP ' + QUOTENAME(@group) + ' ADD DATABASE ' + QUOTENAME(@databasename) + ';'
print @PrimaryAG --- *** CHANGE HERE for EXEC master..sp_executesql @sqltext
-- join the AG group on secondary
select @SecondaryAG = 'ALTER DATABASE ' + QUOTENAME(@databasename) + ' SET HADR AVAILABILITY GROUP = ' + QUOTENAME(@group) + ' ;'
print @SecondaryAG
select @remotesql2 = N'EXEC ' + QUOTENAME(@linkedserverName) + '.master..sp_executesql @sqlrestore;'
print @remotesql2 --- *** CHANGE HERE for EXEC master..sp_executesql @SecondaryAG
-- finally update the table
update AlwaysON_Candidates
set IsAlwaysOnMember = 1
where DatabaseName = @databasename
-- go to another database if it is added newly
select @databasename = min(DatabaseName)
from AlwaysON_Candidates
where IsAlwaysOnMember = 0
and DatabaseName > @databasename
end
ここにはたくさんの警告があります。データ/ログのパスがすべてのレプリカで一致している、エラー処理が追加されていないなどのシナリオで、これを非常に限られた方法でテストしました。このストアドプロシージャは、DDLトリガーから呼び出すことができます。方法、キンが示唆したように、または仕事から、またはあなたは何を持っています。
追加コメントをインラインで参照してください。
CREATE PROCEDURE dbo.AddNewDBsToGroup
@group SYSNAME = N'your_group_name', -- *** SPECIFY YOUR GROUP NAME HERE ***
@path SYSNAME = N'\\atel-web-be2\backups\',
@debug BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@sql NVARCHAR(MAX) = N'',
@remote_sql NVARCHAR(MAX) = N'';
DECLARE @t TABLE(db SYSNAME);
INSERT @t SELECT name FROM sys.databases
WHERE replica_id IS NULL AND database_id > 4;
DECLARE @r TABLE(s NVARCHAR(512));
-- get the *healthy* replicas available for this group
-- you'll need error handling to handle cases where any
-- of the replicas is currently *not* healthy. This
-- script does not tell you this happened.
INSERT @r SELECT r.replica_server_name
FROM sys.availability_groups AS g
INNER JOIN sys.dm_hadr_availability_group_states AS s
ON g.group_id = s.group_id
INNER JOIN sys.availability_replicas AS r
ON g.group_id = r.group_id
AND r.replica_server_name <> @@SERVERNAME
WHERE g.name = @group
AND s.primary_replica = @@SERVERNAME
AND s.primary_recovery_health_desc = 'ONLINE'
AND s.synchronization_health_desc = 'HEALTHY';
-- add the database to the group on the primary:
SELECT @sql += N'ALTER AVAILABILITY GROUP '
+ QUOTENAME(@group) + ' ADD DATABASE ' + QUOTENAME(db) + ';'
FROM @t;
IF @debug = 1
BEGIN
PRINT @sql;
END
ELSE
BEGIN
EXEC master..sp_executesql @sql;
END
-- back up the database locally:
-- this assumes your database names don't have characters illegal for paths
SET @sql = N'';
SELECT @sql += N'BACKUP DATABASE ' + QUOTENAME(db) -- ** BACKUP HAPPENS HERE **
+ ' TO DISK = ''' + @path + db + '.BAK'' WITH COPY_ONLY, FORMAT, INIT, COMPRESSION;
BACKUP LOG ' + QUOTENAME(db) +
' TO DISK = ''' + @path + db + '.TRN'' WITH INIT, COMPRESSION;'
FROM @t;
IF @debug = 1
BEGIN
PRINT @sql;
END
ELSE
BEGIN
EXEC master..sp_executesql @sql;
END
-- restore the database remotely:
-- this assumes linked servers match replica names, security works, etc.
-- it also assumes that each replica has the exact sime data/log paths
-- (in other words, your restore doesn't need WITH MOVE)
SET @sql = N'';
SELECT @sql += N'RESTORE DATABASE ' + QUOTENAME(db) -- ** RESTORE HAPPENS HERE **
+ ' FROM DISK = ''' + @path + db + '.BAK'' WITH REPLACE, NORECOVERY;
RESTORE LOG ''' + @path + db + '.TRN'' WITH NORECOVERY;
ALTER DATABASE ' + QUOTENAME(db) + ' SET HADR AVAILABILITY GROUP = '
+ QUOTENAME(@group) + ';'
FROM @t;
SET @remote_sql = N'';
SELECT @remote_sql += N'EXEC ' + QUOTENAME(s) + '.master..sp_executesql @sql;'
FROM @r;
IF @debug = 1
BEGIN
PRINT @sql;
PRINT @remote_sql;
END
ELSE
BEGIN
EXEC sp_executesql @remote_sql, N'@sql NVARCHAR(MAX)', N'SELECT @@SERVERNAME;';
END
END
GO
ストアドプロシージャを作成したら、この方法で呼び出し、メッセージペインを見て、実行前に適切なグループ、データベース、サーバーが識別されているかどうかを確認できます。
EXEC dbo.AddNewDBsToGroup @debug = 1;
それが正しいことを行うと確信している場合(そして「正しいこと」が何であるかを完全に理解している場合)、それを次のように変更します。
EXEC dbo.AddNewDBsToGroup @debug = 0;
失敗しても心配しないでください。
これを行うのは非常に簡単な練習です。これは、私がいくつかのクールなことをするために私が家に持っているスクリプトの縮小版です。いくつかのメモ:
データベースが作成されたら、AlwaysOn初期化のためにキューに入れます。暗黙のトランザクションが発生するため、CREATE DATABASE
からすぐに実行することはできません。それ以外の場合、発生する必要のあるバックアップはSQLによってブロックされます。
私のコードでは、作成する「可用性グループ」が自動的に検出されます。これは、CREATE DATABASE
を発行したときに接続していたグループです(アプリケーションがAlwaysOnに自己入力できるようにします)。サーバー名に直接接続する場合、AG名を見つけることができないため、自動複製は行われません。
'RPC'および 'RPC OUT'権限と適切な資格情報を持つ他のサーバー(名前はホスト名と同じである必要があります)を指す可用性グループのすべてのサーバーにリンクサーバーが必要です。これは、ほとんどの場合、混合認証を有効にし、「sa」タイプのアカウントを持つことを意味します。
'master'からHADR_REPLICATE_QUEUE
プロシージャを定期的に呼び出します。 5-10分ごとに言ってください。つまり、すぐにデータベースにHAが存在することはありませんが、まもなく発生します。
すべてのサーバーでバックアップが行われるパスは、グループ内のすべてのサーバー(つまり、UNC共有)にアクセスできる必要があります。インストール時に設定されたデフォルトのインスタンスバックアップパスから自動的にスクレイピングします。
ご覧のとおり、私にはできる限り手を加えないように設計されています。 CREATE LOGIN
も同様の方法でキャッチし、可能な限りすべてのノードの一貫性を維持します。
スクリプトは次のようになります。
/**
* AlwaysOn Self-Population Script
* By: Steve Gray / [email protected]
* Usage: Free, but buy me a beer if you're ever in Brisbane.
**/
USE [master]
GO
IF EXISTS (SELECT * FROM sys.tables WHERE name='hadr_pending_replicate')
BEGIN
DROP TABLE hadr_pending_replicate;
END;
GO
CREATE TABLE hadr_pending_replicate (database_name VARCHAR(512) PRIMARY KEY NOT NULL, availability_group_name VARCHAR(2048) NOT NULL);
GO
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name='ddl_hadr_autoreplicate')
BEGIN
DROP TRIGGER ddl_hadr_autoreplicate ON ALL SERVER;
END;
GO
CREATE TRIGGER ddl_hadr_autoreplicate ON ALL SERVER
FOR CREATE_DATABASE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @DatabaseName NVARCHAR(2048)
-- Find the availability group, if the CREATE DATABASE is occuring on an AG listener.
DECLARE @AddToGroupName VARCHAR(512);
SELECT TOP 1
@AddToGroupName = [AG].[name]
FROM
sys.availability_groups AS [AG]
INNER JOIN sys.availability_group_listeners AS [LS] ON [LS].[group_id] = [AG].[group_id]
INNER JOIN sys.availability_group_listener_ip_addresses AS [IP] ON [IP].[listener_id] = [LS].[listener_id]
INNER JOIN sys.dm_exec_connections AS [CN] ON [CN].[local_net_address] = [IP].[ip_address] AND [CN].[local_tcp_port] = [LS].[port]
WHERE
[CN].[session_id] = @@SPID;
SET @DatabaseName = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]', 'nvarchar(128)'));
-- We have to use a queue since initial backups cant happen during the CREATE DATABASE trigger firing.
IF @AddToGroupName IS NOT NULL
BEGIN
PRINT 'Database is queueing for HADR replication';
DELETE FROM hadr_pending_replicate WHERE database_name = @DatabaseName;
INSERT INTO hadr_pending_replicate SELECT @DatabaseName, @AddToGroupName;
END
END;
GO
IF EXISTS (SELECT * FROM sys.procedures WHERE name='hadr_process_replicate')
BEGIN
DROP PROCEDURE hadr_process_replicate;
END;
GO
/**
* This script automatically performs a few tasks when a database is created via a connection
* to a SQL Server availability group listener:
*
* 1) Switch the database from 'SIMPLE' to 'FULL' recovery.
* 2) Perform a full backup to the default backup path for the server.
* 3) Connect to other servers in the availability group and stage a WITH NO RECOVERY restore.
* 4) Add the database to the availability group and initialize AlwaysOn.
*
* For this to work, you must have linked servers on all your nodes with the same name as the Windows
* Host name (i.e. SERVERNAME). If in doubt, look at replica_server_name from sys.availability_replicas.
* Linked servers must have RPC and RPC OUT options set to true. Script assumes that the backup destination
* is accessible to every other server too.
**/
CREATE PROCEDURE hadr_process_replicate
@AddToGroupName VARCHAR(2048),
@DatabaseName VARCHAR(2048)
AS
BEGIN
DECLARE @AvailabilityGroupID UNIQUEIDENTIFIER;
DECLARE @BackupDestination VARCHAR(2048);
DECLARE @BackupSuffix VARCHAR(2048) = '_Initial.bak';
SET @AvailabilityGroupID = (SELECT group_id FROM sys.availability_groups WHERE name=@AddToGroupName);
-- Switch the database to FULL recovery if it was created without it.
IF (SELECT recovery_model FROM sys.databases WHERE name=@DatabaseName) <> 1
BEGIN
PRINT 'Changing recovery model to FULL';
DECLARE @ModeChange NVARCHAR(512) = 'ALTER DATABASE [' + @DatabaseName + '] SET RECOVERY FULL WITH NO_WAIT';
EXEC sp_executesql @ModeChange;
END;
ELSE
BEGIN
PRINT 'Database is already in FULL recovery mode.'
END;
-- Read the default backup path from the SQL Server configuration here. This path needs to be accessible to all the servers in
-- the availability group.
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',N'Software\Microsoft\MSSQLServer\MSSQLServer',N'BackupDirectory', @BackupDestination OUTPUT, 'no_output';
DECLARE @TargetFile VARCHAR(2048) = @BackupDestination + '\' + @DatabaseName + @BackupSuffix;
-- Perform initial backup of the database - Will overwrite any existing file.
PRINT 'Backing up initial database to ' + @TargetFile;
DECLARE @BackupCommand NVARCHAR(2048) = 'BACKUP DATABASE [' + @DatabaseName + '] TO DISK = N''' + @TargetFile + ''' WITH INIT, NOFORMAT, NAME = N''Initial backup for HADR seeding'', SKIP, NOREWIND, NOUNLOAD, STATS = 100';
PRINT ' Command: ' + @BackupCommand
EXEC (@BackupCommand)
PRINT 'Joining database to availability group'
DECLARE @JoinToAG NVARCHAR(2048) = 'ALTER AVAILABILITY GROUP [' + @AddToGroupName + '] ADD DATABASE [' + @DatabaseName + ']';
EXEC sp_executesql @JoinToAG;
-- Loop through all availability replicas
DECLARE @Replicas TABLE (ReplicaName VARCHAR(512))
INSERT INTO @Replicas -- Have to use a table, since T-SQL wasnt giving me
-- all replicas when I did this straight via the cursor.... (Bug?)
SELECT replica_server_name
FROM
sys.availability_replicas
WHERE group_id=CAST(@AvailabilityGroupID AS VARCHAR(512));
DECLARE cur_Replicas CURSOR FOR SELECT ReplicaName FROM @Replicas INNER JOIN sys.servers [SV] ON [SV].[name] = [ReplicaName] AND [SV].[is_linked] = 1 ORDER BY [ReplicaName];
OPEN cur_Replicas;
DECLARE @CurrentReplica VARCHAR(255)
FETCH NEXT FROM cur_Replicas INTO @CurrentReplica;
WHILE @@FETCH_STATUS >= 0
BEGIN
PRINT 'Restoring initial backup to ' + @CurrentReplica;
DECLARE @RestoreCommand VARCHAR(2048) = 'RESTORE DATABASE [' + @DatabaseName + '] FROM DISK = N''' + @TargetFile + ''' WITH NORECOVERY, NOUNLOAD, REPLACE, STATS = 5;'
-- The 'inception' moment.
DECLARE @DoubleDynamicRestore NVARCHAR(2048) = 'EXEC (''' + REPLACE(@RestoreCommand, '''', '''''') + ''') AT [' + @CurrentReplica + ']';
PRINT @DoubleDynamicRestore
EXEC sp_executesql @DoubleDynamicRestore;
PRINT 'Bringing replica online'
DECLARE @DynamicAddHADR NVARCHAR(2048) = 'EXEC (''ALTER DATABASE [' + @DatabaseName + '] SET HADR AVAILABILITY GROUP = [' + @AddToGroupName +'];'') AT [' + @CurrentReplica +']';
EXEC sp_executesql @DynamicAddHADR
FETCH NEXT FROM cur_Replicas INTO @CurrentReplica;
END;
CLOSE cur_Replicas;
DEALLOCATE cur_Replicas;
END;
GO
IF EXISTS (SELECT * FROM sys.procedures WHERE name='hadr_replicate_queue')
BEGIN
DROP PROCEDURE hadr_replicate_queue;
END;
GO
/**
* Process all pending HADR replicates.
**/
CREATE PROCEDURE hadr_replicate_queue
AS
BEGIN
DECLARE cur_ReplicationTask CURSOR FOR
SELECT database_name, availability_group_name FROM hadr_pending_replicate WITH(HOLDLOCK)
OPEN cur_ReplicationTask;
DECLARE @DB VARCHAR(512), @AG VARCHAR(2048)
FETCH NEXT FROM cur_ReplicationTask INTO @DB, @AG
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC hadr_process_replicate @AddToGroupName = @AG, @DatabaseName = @DB
FETCH NEXT FROM cur_ReplicationTask INTO @DB, @AG
END;
DELETE FROM hadr_pending_replicate;
CLOSE cur_ReplicationTask;
DEALLOCATE cur_ReplicationTask
END;
GO
プロセスの中核は次のとおりです。
質問があればコメントしてください。
私は、MSDNで作業してスクリプトを変更することで、答えを見つけました。
xp_cmdshell 'del /F /Q /S \\atel-vm-test\backup\*.*'
--drop table #dbs
--deallocate adddbs
IF OBJECT_ID('dbo.#dbs', 'U') IS NOT NULL
DROP TABLE dbo.#dbs
--IF CURSOR_STATUS('global','adddbs')>=-1
--BEGIN
-- DEALLOCATE adddbs
--END
IF (SELECT CURSOR_STATUS('global','adddbs')) >=0
BEGIN
DEALLOCATE adddbs
END
create table #dbs(a int primary key identity, dbname varchar(100))
declare @nextdb varchar(100)
declare @restorestring varchar(200)
--Populate temp table
insert into #dbs(dbname)
--select name from sys.databases where create_date between getdate()-1 and getdate()
select name from sys.databases
where group_database_id is null and replica_id is null
and name not in('master','model','msdb','tempdb')
--Create a cursor to
declare adddbs cursor for
select dbname from #dbs
open adddbs
FETCH NEXT FROM adddbs
INTO @nextdb
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ('BACKUP DATABASE ' + @nextdb + ' TO DISK = ' + '''\\atel-vm-test\backup\' + @nextdb + 'initialize.bak''')
EXEC ('ALTER AVAILABILITY GROUP [atel-testAG] ADD DATABASE ' + @nextdb)
EXEC ('BACKUP DATABASE ' + @nextdb + ' TO DISK = ' + '''\\atel-vm-test\backup\' + @nextdb + '.bak''')
EXEC ('BACKUP LOG ' + @nextdb + ' TO DISK = ' + '''\\atel-vm-test\backup\' + @nextdb + '_log.bak''')
set @restorestring='sqlcmd -S atel-vm-test2 -E -Q"RESTORE DATABASE ' + @nextdb + ' FROM DISK = ' + '''\\atel-vm-test\backup\' + @nextdb + '.bak''' + ' WITH NORECOVERY, NOUNLOAD, STATS = 5"'
exec xp_cmdshell @restorestring
print 'sqlcmd -S [atel-vm-test2] -E -Q"RESTORE DATABASE ' + 'agd2' + ' FROM DISK = ' + '''\\atel-vm-test\backup\' + 'agd2' + '.bak''' + ' WITH NORECOVERY, NOUNLOAD, STATS = 5"'
set @restorestring='sqlcmd -S atel-vm-test2 -E -Q"RESTORE LOG ' + @nextdb + ' FROM DISK = ' + '''\\atel-vm-test\backup\' + @nextdb + '_log.bak''' + ' WITH NORECOVERY, NOUNLOAD, STATS = 5"'
exec xp_cmdshell @restorestring
set @restorestring='sqlcmd -S atel-vm-test2 -E -Q"ALTER DATABASE ' + @nextdb + ' SET HADR AVAILABILITY GROUP = [atel-testag]"'
exec xp_cmdshell @restorestring
FETCH NEXT FROM adddbs
INTO @nextdb
END
CLOSE adddbs
DEALLOCATE adddbs
--end
次のステップ:
atel-testAG
を独自の可用性グループ名に置き換えます。\\atel-vm-test\backup
をサーバーの共有バックアップ場所に置き換えます。\\atel-vm-test2
をセカンダリサーバーの名前に置き換えます。このジョブは、プライマリサーバーから実行されるようにスケジュールされています。 (変数「プライマリサーバー」から実行するように設定していません。今のところ、atel-vm-test
というプライマリサーバーで実行しています。
SQLサーバーで実行するためのxp_cmdshell
関数権限があることを確認してください。
エラーなしで実行できるようになり、1時間ごとに実行されるようにスケジュールされたSQLジョブになりました。期待どおりに動作します。援助をありがとう。
以下は、20分ごとにSQL Serverエージェントジョブとして実行する必要がある、完成した現在動作しているスクリプトです。そうなる:
単一のSQLインスタンスを持つSQLサーバーまたは2番目のSQLインスタンスで作業します。 2番目のSQLインスタンスがこのスクリプトを使用している場合は、バックアップパスの2番目の名前を共有する必要があります。
このスクリプトがSSMSコンソールで手動で実行されている場合は、最初に "DROP TABLE dbo。#dbs"コマンドを実行する必要があります(このスクリプトが以前に実行されていた場合)。何らかの理由で、このコマンドはSSMSでこのスクリプトを手動で実行しても読み取られませんが、SQL Serverエージェントジョブとして実行すると機能します。 (????)
\ backupsの場所は、このスクリプトでハードコーディングされています。必要に応じてこれを変更してください。また、SQLサーバーのSSMSコンソールでコマンド機能「xp_cmdshell」を有効にする必要があります。調べるためにそれをグーグル;それは簡単なコマンド呼び出しです。これは、1つのプライマリと1つのセカンダリを備えた2-SQLサーバー構成で実行するように設計されています。
xp_cmdshell 'del /F /Q /S \\atel-web\be1\backups\*.*'
exec xp_cmdshell 'del /F /Q /S \\atel-web\be2\backups\*.*'
USE master
DECLARE @secondaryservername nvarchar(50)
DECLARE @primaryservername nvarchar(50)
DECLARE @availabilitygroup nvarchar(50)
SET @secondaryservername = (select replica_server_name AS Servername from sys.dm_hadr_availability_replica_states
, sys.dm_hadr_availability_replica_cluster_states
where role_desc = 'SECONDARY' AND sys.dm_hadr_availability_replica_states.replica_id =
sys.dm_hadr_availability_replica_cluster_states.replica_id)
SET @primaryservername = (select replica_server_name AS Servername from sys.dm_hadr_availability_replica_states
, sys.dm_hadr_availability_replica_cluster_states
where role_desc = 'PRIMARY' AND sys.dm_hadr_availability_replica_states.replica_id =
sys.dm_hadr_availability_replica_cluster_states.replica_id)
SET @availabilitygroup = (SELECT name FROM [sys].[availability_groups])
IF OBJECT_ID('dbo.#dbs', 'U') IS NOT NULL
DROP TABLE dbo.#dbs
IF (SELECT CURSOR_STATUS('global','adddbs')) >=0
BEGIN
DEALLOCATE adddbs
END
create table #dbs(a int primary key identity, dbname varchar(100))
declare @nextdb varchar(100)
declare @restorestring varchar(400)
--Populate temp table
insert into #dbs(dbname)
select name from sys.databases
where group_database_id is null and replica_id is null
and name not in('master','model','msdb','tempdb')
--Create a cursor to
declare adddbs cursor for
select dbname from #dbs
open adddbs
FETCH NEXT FROM adddbs
INTO @nextdb
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ('ALTER DATABASE' + '[' + @nextdb + ']' + 'set RECOVERY FULL')
EXEC ('BACKUP DATABASE ' + '[' + @nextdb + ']' + ' TO DISK = ' + '''\\' +@primaryservername+'\backups\' + '[' + @nextdb + ']' + 'initialize.bak''')
EXEC ('ALTER AVAILABILITY GROUP ['+ @availabilitygroup +'] ADD DATABASE ' + '[' + @nextdb + ']')
EXEC ('BACKUP DATABASE ' + '[' + @nextdb + ']' + ' TO DISK = ' + '''\\'@primaryservername+'\backups\' + '[' + @nextdb + ']' + '.bak''')
EXEC ('BACKUP LOG ' + '[' + @nextdb + ']' + ' TO DISK = ' + '''\\'@primaryservername+'\backups\' + '[' + @nextdb + ']' + '_log.bak''')
set @restorestring='sqlcmd -S ' +@secondaryservername+' -E -Q"RESTORE DATABASE ' + '[' + @nextdb + ']' + ' FROM DISK = ' + '''\\' +@primaryservername +'\backups\' + '[' + @nextdb + ']' + '.bak''' + ' WITH NORECOVERY, NOUNLOAD, STATS = 5"'
exec xp_cmdshell @restorestring
set @restorestring='sqlcmd -S ' +@secondaryservername+' -E -Q"RESTORE LOG ' + '[' + @nextdb + ']' + ' FROM DISK = ' + '''\\' +@primaryservername+'\backups\' + '[' + @nextdb + ']' + '_log.bak''' + ' WITH NORECOVERY, NOUNLOAD, STATS = 5"'
exec xp_cmdshell @restorestring
set @restorestring='sqlcmd -S ' +@secondaryservername+' -E -Q"ALTER DATABASE ' + '[' + @nextdb + ']' + ' SET HADR AVAILABILITY GROUP = [' + @availabilitygroup +']"'
exec xp_cmdshell @restorestring
FETCH NEXT FROM adddbs
INTO @nextdb
END
CLOSE adddbs
DEALLOCATE adddbs