USE [master]
GO
-- 시작안되는 경우도 발생하기 때문에 startDt 기본값을 넣지 않음.
CREATE TABLE [dbo].[tblBackupDB](
[dbName] [varchar](50) NULL,
[startDt] [datetime] NULL,
[endDt] [datetime] NULL,
[msg] [ntext] NULL,
[mdfSize] [int] NULL,
[ldfSize] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
2. 백업을 위한 프로시저 생성, DATEPART를 이용해 특정 요일마다 풀백업과 차등백업을 반복하도록 설정.
샘플을 위해 특정 요일에 풀백업 그 외 차등백업으로 규정하였으나
적절한 풀백업과 차등백업을 번갈아가며 환경에 맞는 주기를 설정합니다.
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_DataBaseBackup]
AS
BEGIN
DECLARE @dbName varchar(4000), @SQL varchar(4000)
DECLARE @yoil int , @mdfSize int , @ldfSize int
SELECT @yoil = DATEPART(WEEKDAY,GETDATE())
-- 백업대상 기록 , 시스템 디비는 제외
INSERT INTO master.dbo.tblBackupDB(dbName)
SELECT name
FROM sys.databases
WHERE UPPER(name) NOT IN ('MASTER','MODEL','MSDB','TEMPDB')
-- 서버 아이피 체크
declare @ip_v4 varchar(16)
SELECT DISTINCT @ip_v4 = local_net_address
FROM sys.dm_exec_connections
WHERE local_net_address IS NOT NULL and local_net_address <> '127.0.0.1'
DECLARE bk_cursor CURSOR FOR
SELECT name
FROM sys.databases
WHERE UPPER(name) NOT IN ('MASTER','MODEL','MSDB','TEMPDB')
OPEN bk_cursor
FETCH NEXT FROM bk_cursor
INTO @dbName
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
-- mdf 파일 사이즈
SELECT @mdfSize = SUM(size)*8/1024 --MB
FROM sys.databases
JOIN sys.master_files
ON sys.databases.database_id=sys.master_files.database_id
WHERE sys.databases.name = @dbName and type='0'
-- ldf 파일 사이즈
SELECT @ldfSize = SUM(size)*8/1024 --MB
FROM sys.databases
JOIN sys.master_files
ON sys.databases.database_id=sys.master_files.database_id
WHERE sys.databases.name = @dbName and type='1'
-- 백업시작 기록/용량 기록
UPDATE master.dbo.tblBackupDB
SET startDt = GETDATE() , mdfSize = @mdfSize, ldfSize = @ldfSize
WHERE dbname = @dbName
AND startDt is null
IF @yoil = 7 -- 토요일은 풀백업
BEGIN
--풀백업
SET @SQL = 'BACKUP DATABASE ['+@dbName+'] TO DISK = N''D:\Backup\'+convert(varchar(30), getdate(),112)+'_'+@dbName+'.bak'' WITH COMPRESSION, INIT, NAME = '''+@dbName+' - Backup'', SKIP, NOREWIND, NOUNLOAD, STATS = 10;'
END
ELSE -- 주간은 차등백업
BEGIN
--차등백업
SET @SQL = 'BACKUP DATABASE ['+@dbName+'] TO DISK = N''D:\Backup\'+convert(varchar(30), getdate(),112)+'_'+@dbName+'.bak'' WITH DIFFERENTIAL , NOFORMAT, NOINIT, NAME = N'''+@dbName+' - Backup'', SKIP, NOREWIND, NOUNLOAD, STATS = 10;'
END
--print @SQL
EXEC (@SQL)
-- 백업종료 기록
UPDATE master.dbo.tblBackupDB
SET endDt = GETDATE()
WHERE dbname = @dbName
AND CONVERT(CHAR(10),startDt,23) = CONVERT(CHAR(10),GETDATE(),23)
AND endDt IS NULL
END TRY
BEGIN CATCH
-- 에러 기록
UPDATE master.dbo.tblBackupDB
SET msg = 'ERROR_NUMBER : ' + CAST(ERROR_NUMBER() AS VARCHAR) + '
ERROR_MESSAGE: ' + ERROR_MESSAGE()
WHERE dbname = @dbName
AND CONVERT(CHAR(10),startDt,23) = CONVERT(CHAR(10),GETDATE(),23)
AND endDt IS NULL
END CATCH
FETCH NEXT FROM bk_cursor
INTO @dbName
END
CLOSE bk_cursor;
DEALLOCATE bk_cursor;
-- FREEPROCCACHE 는 메모리 상에 전체 캐시를 비우기
-- https://bit.ly/3icmJ85
DBCC FREEPROCCACHE;
END
3. 백업 후 남겨진 기록과 msdb.dbo.backupset 테이블 데이터를 참조하여 리포팅 메일 발송.
메일 발송을 위해 데이터베이스 메일 구성이 되어있어야 합니다.
html 코딩은 개인 취향대로.. msdb.dbo.backupset 에는 생각보다 많은 정보가 들어있습니다.
Use <database>
SELECT execquery.last_execution_time AS [Date Time], execsql.text AS [Script] FROM sys.dm_exec_query_stats AS execquery
CROSS APPLY sys.dm_exec_sql_text(execquery.sql_handle) AS execsql
ORDER BY execquery.last_execution_time DESC
SELECT
A.name,
case description when '설명이 없습니다.' then '' else description end as description,
CASE convert(
nvarchar(3),
[freq_type],
3
) WHEN 4 THEN N' 매일' WHEN 8 THEN N' 매주 ' + CASE WHEN [freq_interval] & 1 = 1 THEN N'일' ELSE '' END
+ CASE WHEN [freq_interval] & 2 = 2 THEN ' 월' ELSE '' END + CASE WHEN [freq_interval] & 4 = 4 THEN ' 화' ELSE '' END + CASE WHEN [freq_interval] & 8 = 8 THEN ' 수' ELSE '' END + CASE WHEN [freq_interval] & 16 = 16 THEN N' 목' ELSE '' END + CASE WHEN [freq_interval] & 32 = 32 THEN N' 금' ELSE '' END + CASE WHEN [freq_interval] & 64 = 64 THEN N' 토' ELSE '' END WHEN 16 THEN N'하루 한번 '
+ CAST(
[freq_interval] AS VARCHAR(3)
) + N' 매달 ' + CAST(
[freq_recurrence_factor] AS VARCHAR(3)
) + N' 매달' WHEN 32 THEN N'발생 ' + CASE [freq_relative_interval] WHEN 1 THEN N'첫째' WHEN 2 THEN N'둘째' WHEN 4 THEN N'셋째' WHEN 8 THEN N'넷째' WHEN 16 THEN N'마지막' END + ' ' + CASE [freq_interval] WHEN 1 THEN N'일' WHEN 2 THEN N'월' WHEN 3 THEN N'화' WHEN 4 THEN N'수' WHEN 5 THEN N'목' WHEN 6 THEN N'금' WHEN 7 THEN N'토' WHEN 8 THEN N'일' WHEN 9 THEN N'평일' WHEN 10 THEN N'주말' END + N' 모든 ' + CAST(
[freq_recurrence_factor] AS VARCHAR(3)
) + N' 매달' END AS [Recurrence],
CASE convert(
nvarchar(3),
[freq_subday_type],
3
) WHEN 1 THEN STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_start_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) WHEN 2 THEN N'주기적 발생 ' + CAST(
[freq_subday_interval] AS VARCHAR(3)
) + N' 초(s) 간격 ' + STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_start_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) + ' & ' + STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_end_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) WHEN 4 THEN N'주기적 발생 ' + CAST(
[freq_subday_interval] AS VARCHAR(3)
) + N' 분(s) 간격 ' + STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_start_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) + ' & ' + STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_end_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) WHEN 8 THEN N'주기적 발생 ' + CAST(
[freq_subday_interval] AS VARCHAR(3)
) + N' 시간(s) 간격 ' + STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_start_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) + ' & ' + STUFF(
STUFF(
RIGHT(
'000000' + CAST(
[active_end_time] AS VARCHAR(6)
),
6
),
3,
0,
':'
),
6,
0,
':'
) END [Frequency], D.step_id, D.step_name, D.command
FROM msdb.dbo.sysjobs A
INNER JOIN msdb.dbo.sysjobschedules B ON A.job_id = B.job_id
INNER JOIN msdb.dbo.sysschedules C ON B.schedule_id = C.schedule_id
INNER JOIN msdb.dbo.sysjobsteps D ON A.job_id = D.job_id
ORDER BY A.name
SELECT r.session_id,r.command
,cast(CONVERT(NUMERIC(6,2),r.percent_complete) as varchar) + ' %' AS [Percent Complete]
,CONVERT(VARCHAR(20),DATEADD(ms,r.estimated_completion_time,GetDate()),20) AS [ETA Completion Time]
,CONVERT(NUMERIC(10,2),r.total_elapsed_time/1000.0/60.0) AS [Elapsed Min]
,CONVERT(NUMERIC(10,2),r.estimated_completion_time/1000.0/60.0) AS [ETA Min]
,CONVERT(NUMERIC(10,2),r.estimated_completion_time/1000.0/60.0/60.0) AS [ETA Hours]
,CONVERT(VARCHAR(1000),(SELECT text FROM sys.dm_exec_sql_text(sql_handle))) AS [SQL]
FROM sys.dm_exec_requests r WHERE command IN ('RESTORE DATABASE','BACKUP DATABASE')
-- 프로시저에서 사용하는 테이블 목록
;WITH stored_procedures AS
(
SELECT oo.name AS table_name, o.name,
ROW_NUMBER() OVER(partition by o.name,oo.name ORDER BY o.name,oo.name) AS row
FROM sysdepends d
INNER JOIN sysobjects o ON o.id=d.id
INNER JOIN sysobjects oo ON oo.id=d.depid
WHERE o.xtype = 'P' AND o.name LIKE '%프로시저명%'
)
SELECT name,Table_name FROM stored_procedures
WHERE row = 1
반대로 특정 테이블을 참조하는 프로시저 목록을 조회하는 SQL문 입니다.
-- 특정 테이블을 참조하는 프로시저 목록
;WITH stored_procedures AS
(
SELECT oo.name AS table_name, o.name,
ROW_NUMBER() OVER(partition by o.name,oo.name ORDER BY o.name,oo.name) AS row
FROM sysdepends d
INNER JOIN sysobjects o ON o.id=d.id
INNER JOIN sysobjects oo ON oo.id=d.depid
WHERE o.xtype = 'P' AND oo.name = '테이블명'
)
SELECT name,Table_name FROM stored_procedures
WHERE row = 1
BACKUP DATABASE [test] TO DISK = N'D:\Backup\test_full.bak' WITH NOFORMAT, NOINIT, NAME = N'test-전체 데이터베이스 백업', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
-- 차등백업 1
BACKUP DATABASE [test] TO DISK = N'D:\Backup\test_1.bak' WITH DIFFERENTIAL , NOFORMAT, NOINIT, NAME = N'test-전체 데이터베이스 백업', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
-- 차등백업 2
BACKUP DATABASE [test] TO DISK = N'D:\Backup\test_2.bak' WITH DIFFERENTIAL , NOFORMAT, NOINIT, NAME = N'test-전체 데이터베이스 백업', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
-- 기본 전체 백업 + 차등 복구
문법
RESTORE DATABASE [디비명] FROM DISK = N'풀백업위치'
WITH MOVE '논리적 DB명' TO 'mdf 복구위치'
,MOVE '논리적 LOG명' TO 'ldf 복구위치', NORECOVERY, NOUNLOAD, STATS = 5;
RESTORE DATABASE [tes디비명] FROM DISK = N'차등백업위치' WITH FILE = 1, NOUNLOAD, STATS = 5
RESTORE DATABASE [test3] FROM DISK = N'D:\Backup\test_full.bak'
WITH MOVE 'test' TO 'C:\DATABASE\MSSQL15.MSSQLSERVER\MSSQL\DATA\test3.mdf'
,MOVE 'test_log' TO 'C:\DATABASE\MSSQL15.MSSQLSERVER\MSSQL\DATA\test3.ldf', NORECOVERY, NOUNLOAD, STATS = 5;
RESTORE DATABASE [test3] FROM DISK = N'D:\Backup\test_2.bak' WITH FILE = 1, NOUNLOAD, STATS = 5