2016년 3월 1일 화요일

[SQL] MS-SQL DB 로그 파일 축소 스크립트 - 주기적으로 실행되는 스케줄로 만들기

http://ooz.co.kr/157

바로 이전 DB 포스팅에서 MS-SQL의 DB 로그 파일을 축소하는 쿼리에 대해서 알아보았습니다.

그런데 이 로그 파일이라는 것이 매 번 사용자들이 DB에 접근할 때마다 기록되는 것이다 보니, 한 번 로그 파일을 축소 했다고 해서 영원히 줄어드는 것이 아닙니다. 파일 축소 후에 몇일 몇 주가 지난 후, 로그 파일 용량이 급속도로 증가하는 것을 볼 수 있습니다.

그러면 매번 관리자가 로그 파일들의 용량을 확인해서 축소 시켜주어야 하는데, 여간 번거로운 일이 아닙니다.

그렇다면 이러한 번거로운 작업들을 자동화 시킬 수는 없을까요?

과거 아래 작성했던 2개의 포스팅 내용을 결합하면 그 문제를 해결 할 수 있습니다.

- 포스팅 참고하기 - 1) DB 로그 파일 축소 스크립트 : http://ozit.tistory.com/103
2) DB 자동 백업 설정하기 (SQL Server Agent) : http://ozit.tistory.com/86

DB 로그 파일 축소 스크립트를 SQL Server Agent 에 등록하여 정기적으로 로그를 축소시키도록 하는 것입니다.

그러면 바로 한 번 알아보도록 하겠습니다.^^

이번 포스팅은 DB 로그 파일 축소 스크립트와 SQL Server Agent에 대한 자세한 설명은 생략하고, 오직 DB 로그 파일 축소 쿼리를 스케줄로 등록시키는 것에 대한 내용만 포함합니다. 스크립트에 대한 이해 및 SQL Server Agent 에 대해 조금이라도 더 자세한 정보를 알기 원하신다면 위의 2 포스팅을 참조해주세요.^^



1) Microsoft SQL Server Management Studio 에서 SQL Server 에이전트 새작업을 선택합니다.
 * SQL Server 에이전트 트리 메뉴에서 노란 [작업] 폴더 위에서 마우스 우측 버튼 클릭하면 컨텍스트 메뉴가 뜨는데, 여기서 [새 작업]을 선택합니다.





2) 새 작업을 작성합니다.
 * 일반 페이지의 화면입니다. 작업의 이름과 설명을 입력합니다. 설명은 입력하지 않아도 무방합니다.




3) 단계 를 설정합니다.
 * 단계 페이지의 하단에 [새로 만들기] 버튼을 클릭하면 아래와 같이 새 작업 단계 화면이 뜹니다.
 * 단계 이름을 입력합니다.
 * 로그 축소할 파일의 데이터베이스를 [데이터베이스(D):] 선택박스에서 선택합니다. 그리고  로그 파일을 축소하는 스크립트를 하단 입력창에 입력합니다. (위의 첫번째 참고 포스팅에는 해당 스크립트의 동작에 대한 자세한 설명이 포함되어 있습니다.)



USE [@@DB_NAME@@] -- 여기에 DB이름을 입력합니다. 데이터베이스(D): 에서 선택한 DB 이름을 입력하면 됩니다.
GO
-- Declare variables
DECLARE @SqlStatement as nvarchar(max)
DECLARE @LogFileLogicalName as sysname


-- Alter the database to simple recovery
SET @SqlStatement = 'ALTER DATABASE ' + DB_NAME() + ' SET RECOVERY SIMPLE'
EXEC ( @SqlStatement )


-- Make sure it has been altered
SELECT [name], [recovery_model_desc] FROM sys.databases WHERE [name] = DB_NAME()


-- Set the log file name variable
SELECT @LogFileLogicalName = [Name] FROM sys.database_files WHERE type = 1


-- Shrink the logfile
DBCC Shrinkfile(@LogFileLogicalName, 1)


-- Alter the database back to FULL
SET @SqlStatement = 'ALTER DATABASE ' + DB_NAME() + ' SET RECOVERY FULL'
EXEC ( @SqlStatement )


-- Make sure it has been changed back to full
SET @SqlStatement = 'SELECT [name], [recovery_model_desc] FROM ' + DB_NAME() + '.sys.databases WHERE [name] = ''' + DB_NAME() + ''''
EXEC ( @SqlStatement )

 



4) 일정 을 설정합니다.
 * 일정 페이지의 하단에 [새로 만들기] 버튼을 클릭하면 아래와 같이 새 작업 일정 화면이 뜹니다.
 * 일정 이름을 입력합니다.
 * 일정은 매일, 주간, 격주, 월간 등 다양하게 설정 가능하며, 시간대, 시간 간격 되풀이 등 도 설정할 수 있습니다. 저는 아래 화면에서 보시는 것처럼 매 2주마다 일요일 오전 2시에 위의 스크립트가 실행되도록 설정하였습니다.





5) 모두 확인을 누르고, 작업 등록을 완료합니다. 그리고 정상 동작하는지 테스트합니다.
 다시 SQL Server 에이전트의 작업 목록으로 가보시면 방금 등록한 작업 스케줄이 등록된 것을 확인할 수 있습니다. (만약 보이지 않는다면 새로 고침하시면 나옵니다.)
 스케줄은 격주로 매 일요일 새벽 2시에 동작하도록 해 놓았는데, 이 스케줄의 스크립트에 문제가 있는지 여부를 그 때까지 기다릴 수 없습니다. 새벽 2시에 정상 동작하는지 확인하기는 어렵죠?^^
 그래서 컨텍스트 메뉴에서 - [작업 시작] 메뉴를 선택하면 스케줄 일정에 상관없이 작업을 즉시 실행시킵니다. 이를 통해 작성한 SQL 쿼리가 올바르게 동작하는지 여부를 확인할 수 있습니다.



아래의 화면에서 보듯이 작업이 정상적으로 수행된 것을 볼 수 있습니다.


그러면 실제 해당 DB의 로그 파일이 정상적으로 축소되었는지 확인해 봐야 되지 않을까요?


위의 파일은 스크립트에 로그 파일 축소를 위해 등록한 DB 파일로 작업 전에 500여MB 였던 로그 파일이, 에이전트 작업 완료 후, 1MB로 축소된 것을 확인할 수 있습니다. 날짜도 축소를 하여 파일이 수정되었으므로 수정된 날짜(2월 3일)로 변경되었습니다.

SQL 에이전트는 이번 포스팅도 그렇고, 이 전에 작성한 포스팅도 그렇고, 스크립트로 작성할 수 있는 모든 작업들을 스케줄로 등록하여 관리할 수 있어 여러모로 유용합니다. 다양한 작업들을 응용하여 등록하고 사용해 보세요^^

[SQL] MS-SQL DB 로그 파일 축소하기

http://ooz.co.kr/103

MS-SQL은 실제 데이터가 저장된 데이터베이스 파일(*.mdf)과 데이터베이스의 처리에 대한 로그 파일(*.ldf)로 구성되어 데이터를 관리합니다.

mdf 파일에는 현재 최종적인 데이터의 정보를 가지고 있는 실 데이터를 관리하는 데이터 파일이며,
ldf는 데이터 변화에 따른 로그를 기록 관리 하는 파일입니다. ldf 파일은 데이터 복원에 있어서 중요한 파일이며, 이번 포스팅에서는 이 ldf 파일의 용량을 줄이는 방법에 대해서 설명합니다.

여러 데이터베이스를 관리하다 보면 몇몇 ldf 파일의 크기가 상당히 커지는 경우가 발생합니다.
해당 DB의 접근이 많아 트랜잭션 로그가 지속적으로 또 급격히 쌓이거나 하는 경우입니다. ldf 파일을 서버 관리자가 정기적으로 별도의 백업을 하지 않거나 또는 정기 백업 시스템에 문제가 생겨서 ldf 파일이 제대로 관리되지 않는다면 (또 용량 제한을 두지 않는다면) 무한히 커지게 될 것입니다.

사실 용량이 커지는 것 자체로 문제가 되는 것은 아니지만,
로그 파일 용량이 한계치에 도달하거나 서버의 HDD를 모두 써버릴 만큼 용량이 커지게 되면 해당 DB 또는 같은 서버에 존재하는 모든 DB로의 접근이 실패하거나 문제가 발생할 수 있습니다.


먼저 DB서버에서 더 이상 데이터를 쓸 수 없을 만큼 용량이 한계치에 도달하게 되면 SELECT를 제외한 모든 DML(Data Manipulation Language)의 처리(INSERT, UPDATE 등)가 실패하기 됩니다.
그 이유는 데이터에 변화를 주는 조작이 있게 되면 로그 파일에 기록을 해야 하는데, 더 이상 기록을 할 수 있는 공간이 없기 때문입니다. SELECT 동작은 별도의 로그 파일에 기록하지 않기 때문에 용량이 꽉찬 DB서버에서도 정상적으로 동작합니다.
웹사이트를 서비스하고 있는 경우, 사용자가 로그인을 시도하는 경우, DB에 로그인 히스토리를 기록하는 처리 등을 수행한다면 해당 웹 사이트에 더 이상 사용자가 로그인하지 못하게 됩니다.

그러면 별도의 백업을 한 다음, 또는 백업이 필요없다 판단되어 ldf 파일의 용량을 초기화 시키고 싶을 경우가 있습니다. (ldf 파일을 초기화 시켜도 실 데이터베이스 파일(mdf) 에 영향을 미치는 것은 아니므로, 현재 mdf 데이터만 제대로 유지하면 된다면 ldf 파일 용량 축소 시키는 작업은 DB데이터나 서비스에 문제가 되지는 않습니다.)

그러한 경우에는 다음의 Transaction-SQL로 작성된 쿼리를 실행시키시면 되겠습니다.
코드 출처 : http://ottoradke.com

간단히 아래 코드의 YourDatabaseName 이라고 된 부분에 로그 파일을 축소할 DB이름을 입려한 후, 쿼리를 실행(F5)하면 됩니다.

------------------------------------------------------------------------------
-- Otto R. Radke - http://ottoradke.com
-- Info: T-SQL script to shrink a database's transaction log. Just set the
-- database name below and run the script and it will shrink the
-- transaction log.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Update the line below with the name of the database who's transaction
-- log you want to shrink.
------------------------------------------------------------------------------
1) USE YourDatabaseName
------------------------------------------------------------------------------
-- Don't change anything below this line.
------------------------------------------------------------------------------
GO
-- Declare variables
DECLARE @SqlStatement as nvarchar(max)
DECLARE @LogFileLogicalName as sysname

-- Alter the database to simple recovery
2) SET @SqlStatement = 'ALTER DATABASE ' + DB_NAME() + ' SET RECOVERY SIMPLE'
EXEC ( @SqlStatement )

-- Make sure it has been altered
3) SELECT [name], [recovery_model_desc] FROM sys.databases WHERE [name] = DB_NAME()

-- Set the log file name variable
4) SELECT @LogFileLogicalName = [Name] FROM sys.database_files WHERE type = 1

-- Shrink the logfile
5) DBCC Shrinkfile(@LogFileLogicalName, 1)

-- Alter the database back to FULL
6) SET @SqlStatement = 'ALTER DATABASE ' + DB_NAME() + ' SET RECOVERY FULL'
EXEC ( @SqlStatement )

-- Make sure it has been changed back to full
7) SET @SqlStatement = 'SELECT [name], [recovery_model_desc] FROM ' + DB_NAME() + '.sys.databases WHERE [name] = ''' + DB_NAME() + ''''
EXEC ( @SqlStatement )
------------------------------------------------------------------------------


1) USE YourDatabaseName
 - 해당 데이터베이스(YourDatabaseName)에 대해 쿼리를 수행할 것을 지정합니다.

2) SET @SqlStatement = 'ALTER DATABASE ' + DB_NAME() + ' SET RECOVERY SIMPLE'
EXEC ( @SqlStatement )
 - DB 복구 모델을 Simple Recovery 로 변경합니다. 다시 말하면 해당 DB의 복구 모델을 단순 복구 모델(Simple) 형태로 전환하는 것인데, MS-SQL에서는 아래의 3가지 복구 모델을 지원합니다.

 1. 전체 복구 모델 - Full Recovery Model
 2. 대량 로그 복구 모델 - Bulked-Log Recovery Model
 3. 단순 복구 모델 - Simple Recovery Model  

DB를 단순 복구 모델로 설정하게 되면 더 이상 해당 DB는 트랜잭션 로그를 기록하지 않고, MS-SQL에 로그 파일 관리가 위임되어 관리자가 직접 로그 파일(ldf)을 접근하여 관리할 수 없게 됩니다.

 * 참고) DB_NAME ( [ database_id ] ) : DB_NAME()은 인자로 Database_Id를 지정하지 않으면 현재 설정된 DB의 이름을 가져옵니다. 여기서는 YourDatabaseName으로 설정된 DB 이름을 반환합니다.

3) SELECT [name], [recovery_model_desc] FROM sys.databases WHERE [name] = DB_NAME()
 - 2)번 단계에서 DB의 복구 모델을 Simple로 변경하였는데, 이 모델이 정상적으로 반영되었는지, 조회하는 것입니다. SELECT하였기 때문에 화면에 변경된 모델이 아래와 같이 출력됩니다.

* SIMPLE 모델로 정상적으로 변경되었습니다.

4) SELECT @LogFileLogicalName = [Name] FROM sys.database_files WHERE type = 1
 - 축소할 로그 파일의 논리적 이름을 가져옵니다. 데이터베이스 파일은 물리적 파일과 연결된 논리적 파일 명을 가지고 있으며, 이는 데이터베이스 속성에서 파일 탭에서 확인할 수 있습니다.
로그 파일 또한 논리적 파일명을 가지고 있고, 이 논리적 파일이 물리적인 파일과 연결되어 있는 것을 알 수 있습니다.



5) DBCC Shrinkfile(@LogFileLogicalName, 1)
  - DB 로그 파일의 용량을 줄이는 명령어를 실행합니다.
   첫번째 인자 : 용량을 축소시킬 로그 파일의 논리적인 이름. 4)번 단계에서 이름을 가져 왔습니다.
   두번째 인자 : 축소시킬 용량(MB)입니다. 1MB로 축소시킵니다.

DBCC SHRINKFILE
     ( { file_name | file_id }
         { [ , target_size ]
             | [ , { EMPTYFILE | NOTRUNCATE | TRUNCATEONLY } ]
        }
    )
 

 Shrinkfile 명령어가 실행되면 다음과 같은 처리 결과 Row가 표시됩니다.


 * DbId : 축소할 파일의 데이터베이스 ID 번호
 * FileId : 축소할 파일의 파일 ID 번호
 * CurrentSize : 현재 파일이 차지하고 있는 8KB 페이지의 수
 * MinimumSize : 파일이 최소한으로 차지할 수 있는 8KB 페이지의 수. 이것은 파일의 최소 크기나 원래 만들어진 크기와 일치합니다.
 * UsedPages 현재 파일에서 사용되는 8KB 페이지의 수
 * EstimatedPages SQL Server에서 예상하는 파일 축소 가능 크기에 해당하는 8KB 페이지의 수

참고로 Shrinkfile 명령어는 Log파일 외에 실제 DB파일에도 사용할 수 있습니다.
DBCC는 MS-SQL의 Transaction-SQL 프로그래밍에서 사용되는 일련의 데이터베이스 콘솔 명령어 집합이며, 좀 더 자세한 정보는 아래 링크에서 확인하실 수 있습니다.
DBCC 링크 : http://en.wikipedia.org/wiki/Database_Console_Commands_(Transact-SQL)


6) SET @SqlStatement = 'ALTER DATABASE ' + DB_NAME() + ' SET RECOVERY FULL'
EXEC ( @SqlStatement )
 - DB 복구 모델을 다시 Full Recovery(전체 복구) 형태로 전환합니다.
 - 전체 복구 모델은 MS-SQL 의 기본 값(제가 테스트한 2008버전에서는!)이며, 기존처럼 트랜잭션 로그를 ldf 파일에 기록하는 형태의 모델입니다. DB의 데이터에 변화를 준 모든 이벤트에 대해 모두 기록하는 형태의 로그입니다.

7) SET @SqlStatement = 'SELECT [name], [recovery_model_desc] FROM ' + DB_NAME() + '.sys.databases WHERE [name] = ''' + DB_NAME() + ''''
EXEC ( @SqlStatement )
 - 6)번 단계에서 DB의 복구 모델을 다시 Full로 변경하였는데, 이 모델이 정상적으로 반영되었는지, 조회하는 것입니다. SELECT하였기 때문에 화면에 변경된 모델이 아래와 같이 출력됩니다.



생각보다 로그 축소 코드는 간단하며, 어려운 내용 또한 없습니다.
그리고 길지 않은 코드 이지만, 이중에서도 DB복구 모델을 변경한다던지, 로그를 출력한다던지 하는 코드를 제외한 실제 DB 로그를 축소시키는 핵심 코드는 4),5)번 코드 뿐입니다. (그와중에도 4번은 로그 파일의 논리 이름을 가져오는 역할만 합니다.)


그리고 마지막으로 중요한 것은!!
로그 파일을 축소시키게 되면 더 이상 로그 파일을 통해 트랜잭션 히스토리 추적으로 DB복구가 불가능하게 되므로 로그 파일 축소 전에 DB 전체 백업하는 것을 권장합니다. (아니, 반드시 하세요!)