Hyun Soo, Lim

대용량 데이터베이스를 복구하는 경우 현재 어떤 작업을 진행중인지 궁금해하면서 빨리 끝나기만을 기다리던 분들이 있을 것으로 생각합니다. 저 역시 그랬구요. 하지만 아래의 옵션을 사용하면 복구 진행과정 중 현재 어느 단계를 수행중인지/어느단계가 시간이 오래걸렸는지 바로 확인이 가능합니다.

[구문]

   DBCCTRACEON(3004, 3605,-1)


    - Trace
Flag 3004 : 백업 또는 복구 수행시 어떤 작업을 진행 중인지 상세히 로그를 보여줌

    - TraceFlag 3605 : SSMS에서 쿼리 수행시 결과창이 아니라 error log에 기록 

 
그럼 간단한 복구 테스트를 통해서 옵션 사용 유무에 따라서 얼마나 차이가 나는지 보도록 하겠습니다.

[테스트]
1. 복구 (옵션 비활성화)

-- 복구수행하기
restoredatabasetestdb_restoreFROM  DISK=N'E:\testdb_simple.bak'WITHfile= 1,
        moveN'testdb'toN'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_01.mdf',
        moveN'testdb_log'toN'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_log_01.ldf',
        moveN'Data01'toN'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_data_01.mdf',
        moveN'Data01_text'toN'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_data_text_01.mdf'

-- 에러로그 보기 (복구에 대한 기록은 5줄만 기록됨)
sp_readerrolog




2. 복구 (옵션 활성화)
-- Errorlog recycle
sp_cycle_errorlog

-- 옵션  활성화
DBCC TRACEON (3004, 3605, -1)

-- 복구수행하기
restore database testdb_restore_option FROM  DISK = N'E:\testdb_simple.bak' WITH file = 1,
        move N'testdb' to N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_restore.mdf',
        move N'testdb_log' to N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_restore_log.ldf',
        move N'Data01' to N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_data_restore.mdf',
        move N'Data01_text' to N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\testdb_data_text_restore.mdf'


-- 에러로그 보기 (복구에 대한 기록은 58줄 기록됨, 옵션 빈활성화에 비하여 약 11배이상 상세로그 기록됨)
sp_readerrolog




-- 옵션 비활성화
DBCC TRACEOFF (3004, 3605, -1)


[의견]
복구 절차 진행시 어디서 시간이 많이 소요되어지는 볼 수 있어 알아두면 도움이 될 것으로 보입니다.

[출처]What Is My Restore Doing?

SQL Server 2012에 신규로 추가된 Analytic Functions 중 LAG 함수 사용 사례를 보도록 하겠습니다.
조회시 데이터 레코드간에 편차를 보여주고 싶을 때 사용하시면 매우 유용한 기능입니다.

함수에 대한 간략히 설명드리고, SQL Server 2008 R2 이하 버전에서는 어떻게 쿼리 작성을 해서 사용했었는지와
함수 사용을 할 경우 성능차이가 있는지 테스트를 해보도록 하겠습니다.

[설명/문법]
1. 설명
 
    - LAG 함수란 동일한 레코드셋안에서 이전에 조회된 레코드에 포함된 값을 접근할 수 있도록 해줍니다. 
      SQL Server 2008 R2 이전 버전에서 동일한 결과를 만들기 위해서는 셀프조인을 활용해야 가능했습니다.

2.  문법 (상세내용은 온라인 도움말 참고)
    - LAG (scalar_expression [,offset] [,default]) OVER ( [partition_by_clause ] order_by_clause )

[테스트]
1. 테스트 환경 셋팅

-- 데이터베이스 생성

create database TESTDB 

use testdb
go

-- 임시 테이블 생성
-- drop table tab_01
create table Tab_01 (
    seqNo int identity(1,1)
,   compareValue int default 0);
go

create clustered index idx_Tab_01_seqNo on Tab_01 (seqNo)
go

-- 20개의 compareValue 랜덤값을 가지는 데이터 입력
insert into tab_01 (compareValue) values (rand()*1000)
go 20

-- 쿼리 성능 보기 위한 옵션 설정
set statistics io on
set statistics time on

2-1. LAG 함수 사용 (Case 1)
select
    seqNo
,   compareValue
,   lag(compareValue, 1, 0) over (order by seqNo) as LagValue
from tab_01 with (readuncommitted)
order by seqNo

-- 결과


-- 성능


-- 실행계획

2-2. 셀프 조인 사용_01 (Case 2, 순차적인 고유번호가 있는 경우)
select a.seqNo, a.CompareValue, b.CompareValue
from tab_01 a with (readuncommitted)
   
left outer join tab_01 b with (readuncommitted) on a.seqNo -1 = b.seqNo
order by a.seqNo

-- 결과


-- 성능


-- 실행계획


2-3. 셀프 조인 사용_02 (Case 3, 순차적인 고유번호가 없는 경우)
select a.seqNo, a.CompareValue, b.CompareValue
from
   
(
     select seqNo, CompareValue, rank() over (order by seqNo asc) RankNo
    
from tab_01 with (readuncommitted)
    )
a
    left outer join
   
(
     
select seqNo, CompareValue, rank() over (order by seqNo asc) RankNo
    
from tab_01 with (readuncommitted)
    )
b
    on a.RankNo -1 = b.RankNo
order by a.seqNo

-- 결과


-- 성능


-- 실행계획


3. 테스트 결과
    - 테스트 결과 IO 사용량의 차이는 아래와 같습니다. LAG 함수 사용이 이전 방식에 비하여 20배이상 성능이 좋은 것을 볼 수 있습니다.
      > Case 1. LAG 함수 사용 : 논리적인 읽기수 = 2
      > Case 2. 셀프 조인 사용_01 : 논리적인 읽기수 = 42
      > Case 3. 셀프 조인 사용_02 : 논리적인 읽기수 = 43

[의견]

    - LAG 함수를 사용하는 경우 조인을 하지 않아도 되기 때문에 읽기수 비용 절감율이 높다.
    - 다양한 활용/응용이 가능한 함수이기 때문에 참고에 적어놓은 아티클은 꼭 보시기를 권장해드리고 싶습니다.

[참고]
1. SQL Server 2012 온라인 도움말
2. SQL Server Mag - SQL Server 2012's Window Functions, Part 2 (Itzik Ben-Gan)

블로그 사이트에 가면 종종 볼 수 있는 기능인 "랜덤블로그 방문"을 DB에서 구현했던 사례를 소개드립니다.
기능에 대해서 설명드리면 "랜던길드" 버튼을 클릭하면 임의로 블로그를 선택해주는 것입니다.
해당 기능 중 여기서 테스트할 내용은 랜덤하게 블로그의 번호를 찾는 부분에 대해서 이야기하려고 합니다.
구현 방식에는 여러가지가 있겠지만 많이 사용하는 2가지 방식에 대한 테스트를 진행해보고 얼마나 성능 차이가
나는지에 대해서 보도록 하겠습니다.

1. 테스트 환경 구성

-- 테이

create table tbl_Blog (

        SeqNo          int            --

,       name           varchar(1000)  --

,       Contents       varchar(6000)  --

)

 

--

create clustered index idx_Article_seqNo on tbl_Blog (seqNo)

 

-- (6400)

insert into tbl_Blog (SeqNo, name, Contents)

select

        seqNo

,       replicate(seqNo, 50) as title

,       replicate(seqNo, 500) as contents

from (

        select

               row_number() over(order by a.name) as [seqNo]

        from sys.objects a

               cross join sys.objects b ) x

order by seqNo

 

-- 

set statistics io on

2. 테스트
2-1. 방법 1 : newid() 함수 사용

select top 1

        SeqNo

,       name

,       Contents

from (

        select

               seqNo

        ,       name

        ,       Contents

        ,       newid() as RandomID

        from tbl_Blog with (readuncommitted) ) x

order by RandomID


[결과]
-- 반복 실행해보시면 블로그번호가 계속 변경되어지는 것을 볼 수 있습니다.


-- 논리적인 읽기 수가 2048페이지로 높은 것을 볼 수 있습니다.

2-2. 방법 2 : rand() 함수 사용

declare @MaxSeqNo int

 

select top 1

        @MaxSeqNo = seqNo

from tbl_Blog with (readuncommitted)

order by SeqNo desc

 

select top 1

        seqNo

,       name

,       Contents

from tbl_Blog with (readuncommitted)

where SeqNo <= rand() *@MaxSeqNo

order by SeqNo desc


[결과]
-- 반복 실행해보시면 블로그번호가 계속 변경되어지는 것을 볼 수 있습니다.


-- 논리적인 읽기 수가 총 6으로 방법1에 비하여 매우 낮음을 볼 수 있습니다.


3. 의견
   > 조금만 응용하면 다양한 서비스에 활용이 가능합니다. (로터리 아이템 구현 등 랜덤이 들어가는 기능들...)
   > 새로운 기능 구현을 고려할 때 반드시 성능 부하가 높지 않을지 확인/검토하시기를 권장드립니다.