Offline Backup은 Database가 메모리에서 내려간 상태에서 받아진 것을 의미한다. 다른 관점에서는 Database에 접속이 이뤄지지 않는, 업무 서비스가 되지 않는 상황에서의 백업을 의미한다.

특정 DBMS에서는 이런 offline backup 개념이 없을 수도 있겠지만, DB2에서 백업은 트랜잭션을 기록하는 로그 관리 방식과 밀접한 관련을 갖는다.

순환로깅 방식을 사용하는 경우 백업은 offline 상태에서 진행되고, 아카이브 로깅 방식(사용한 트랜잭션 로그를 버리지 않고 보관)을 사용하는 경우는 offline, online 백업이 가능해 진다.

대부분의 고객사에서는 서비스가 중지되는 시간을 줄이기 위해 Archive 로깅 모드로 DB를 운영한다. 이런 상황에 offline backup을 못하는 것은 아니지만, 받아 놓은 offline backup을 restore 하다보면 약간 당황스러운 상황이 발생한다.

DB2 걸음마 시절, 고객사에서 갑작스럽게 restore 작업을 하다가 탐탁치않게 보던 시선을 느꼈던 순간이 기억난다..

1. 로깅 방식 확인

   V8 버전 이하의 경우, 혹은 전문 백업 솔루션을 사용하는 경우 좀 더 상세히 살펴봐야 하지만 보통은 아래 변수의 설정값을 통하여 Circular 모드인지 아닌지를 확인할 수 있다.

$ db2 get db cfg for sample | grep -i logarchmeth1

First log archive method                 (LOGARCHMETH1) = OFF
Options for logarchmeth1                  (LOGARCHOPT1) =

LOGARCHMETH1 값이 설정되지 않은 경우 Circular 모드로 운영 중임을 의미한다.

이런 경우는 offline backup 을 restore 하면 바로 db 접속이 가능해 진다.

$ db2 backup db sample to /instance/inst97 compress
Backup successful. The timestamp for this backup image is : 20120423104058

$ db2 drop db sample
DB20000I  The DROP DATABASE command completed successfully.

$ db2 restore db sample from /instance/inst97
DB20000I  The RESTORE DATABASE command completed successfully.

$ db2 connect to sample

  Database Connection Information

Database server        = DB2/LINUXX8664 9.7.4
SQL authorization ID   = INST97
Local database alias   = SAMPLE

그러나 아카이빙 로그 모드로 운영되는 경우 offline backup 이미지를 복원하는 경우 바로 접속되지 않는다.

$ db2 get db cfg for sample | grep -i logarchmeth1

First log archive method                 (LOGARCHMETH1) = DISK:/instance/inst97/archive/
Options for logarchmeth1                  (LOGARCHOPT1) =

$ db2 backup db sample to ~/archive compress

Backup successful. The timestamp for this backup image is : 20120423104901

$ db2 drop db sample

DB20000I  The DROP DATABASE command completed successfully.

$ db2 restore db sample from ~/archive

DB20000I  The RESTORE DATABASE command completed successfully.

$ db2 connect to sample

SQL1117N  A connection to or activation of database "SAMPLE" cannot be made
because of ROLL-FORWARD PENDING.  SQLSTATE=57019

위와 같이 SQL1117N 코드를 반환한다. 보통은 online backup을 복원 후, rollforward 작업을 하지 않는 경우에 발생하는 메시지이다.

위의 문제 해결을 2가지 방법이 존재한다.

$ db2 restore db sample from ~/archive

$ db2 rollforward db sample query status

                                Rollforward Status

Input database alias                   = sample
Number of nodes have returned status   = 1

Node number                            = 0
Rollforward status                     = DB  pending
Next log file to be read               = S0000001.LOG
Log files processed                    =  -
Last committed transaction             = 2012-04-23-02.09.42.000000 UTC



$ db2 rollforward db sample stop

                                 Rollforward Status

Input database alias                   = sample
Number of nodes have returned status   = 1

Node number                            = 0
Rollforward status                     = not pending
Next log file to be read               =
Log files processed                    =  -
Last committed transaction             = 2012-04-23-02.09.42.000000 UTC

DB20000I  The ROLLFORWARD command completed successfully.

혹은 다음과 같이 할 수도 있겠다.

$ db2 restore db sample from ~/archive without rolling forward
DB20000I  The RESTORE DATABASE command completed successfully.

$ db2 rollforward db sample query status


                                Rollforward Status

Input database alias                   = sample
Number of nodes have returned status   = 1

Node number                            = 0
Rollforward status                     = not pending
Next log file to be read               =
Log files processed                    =  -
Last committed transaction             = 2012-04-23-02.09.42.000000 UTC

 

만일 online backup 을 restore 하고 위와 같이 rollforward를 중지하도록 하는 경우, rollforward pending은 풀리지 않는다.

$ db2 rollforward db sample stop

SQL1276N  Database "SAMPLE" cannot be brought out of rollforward pending state
until roll-forward has passed a point in time greater than or equal to
"2012-04-23-02.20.40.000000 UTC", because node "0" contains information later
than the specified time

$ db2 rollforward db sample query status


                                Rollforward Status

Input database alias                   = sample
Number of nodes have returned status   = 1

Node number                            = 0
Rollforward status                     = DB  working
Next log file to be read               = S0000000.LOG
Log files processed                    =  -
Last committed transaction             = 2012-04-23-02.20.40.000000 UTC

$ db2 connect to sample

SQL1117N  A connection to or activation of database "SAMPLE" cannot be made
because of ROLL-FORWARD PENDING.  SQLSTATE=57019

온라인 백업은 백업 이미지에 포함된 archive log 를 추출하여 최소한의 시점 복구(rollforward)를 해 주어야 한다.

IBM에서 타 제조사의 DBMS를 DB2로 변경하는 경우, 관련 작업들을 편하고 자동화할 수 있도록  Tool을 제공한다. 한 때는 MTK(Migration Toolkit) 이라는 것을 제공했으나 현재는 V9.7과 같이 나온 DMT(Data Movement Tool) 이라는 것을 제공하고 있다.

어떤 면에서는 MTK가 좋은데, 또 어떤 면에서는 DMT가 낫다.

1. 비교

항목

MTK

DMT

DB연결방식 ODBC JDBC Type 4
운영체제 Windows, Linux, Unix Windows, Linux, Unix
원본 DBMS Oracle, MSSQL, Sybase ASE, MySQL Oracle,MSSQL, Sybase, Access, MySQL, Postgres, db2, db2 /z
목표 DBMS DB2, Informix DB2
장점 1.GUI 화면에서 선택적 추출
2.파일 대상으로 변환 가능
3.DBMS 고유 함수, 프로시저들을 java routine으로 제공
4.다양한 포맷방식으로 data 추출
1. DB접속을 위한 db client 불필요
2. object 와 제약조건이 분리되어 추출
3. 데이터 분할하여 추출
4. 데이터 추출, 적재작업의 병렬처리
5. 데이터 검증 등의 script 제공
단점 1.object DDL 문과 제약조건이 섞여서 추출됨
2. 추출/변환 시 사용자 요건에 맞는 변경이 제한적임
1. DB를 대상으로 추출/변환
2. MTK에 비해 GUI 기능이 약함
3. Oracle 과 DB2 V9.7에 최적화됨

 

2. MTK 화면

제품 다운로드: http://www.ibm.com/developerworks/data/downloads/migration/mtk/

 

3. DMT 화면

제품 다운로드: http://www.ibm.com/developerworks/data/library/techarticle/dm-0906datamovement/

 

자세한 사용법은 위 URL을 통하여 확인하고 다운받아 사용해보면 될 것 같다.

원본 서버에 접속할 수 없는 환경이여서 고객쪽에서 text 파일로 ddl문을 제공하는 경우는 MTK를 적용하여 이관 작업을 진행할 수 밖에 없을 것이다.

반면 테이블의 데이터가 대용량인 경우, MTK가 실행되는 file system 공간이 여유가 없다면 DMT를 이용하여 데이터를 나눠 추출하여 대용량 데이터를 이관해야되는 상황도 있을 것이다. 또는 원본 DBMS의 클라이언트를 다운받아 설치할 수 없어, 접속이 힘든 경우에도 DMT를 사용해야 될 것이다.

지금 시점에는 V9.7에 최적화된 DMT를 사용하는 것이 일반적이겠지만, DMT 사용을 할 수 없는 경우엔 MTK를 사용을 고려해 봐야 될 듯 하다.

시스템을 관리하다가 오류가 발생해서, 아니면 갑작스럽게 DB 시스템이 느려지거나 heavy한 SQL이 있나 해서 수행 중인 SQL모을 확인해 보고자 하는 경우가 있을 것이다.

IBM에서 무료로 제공하는 모니터링 도구 중 잘 사용되는 것이 db2pd와 db2top 2가지가 있다.

db2pd는 informix의 onstat 의 메커니즘을 적용한 도구로 DB2가 사용하는 메모리에서 정보를 수집하게 해주는 도구이다. 장점은 DB 접속 절차가 없어서 db가 hang이 발생하는 순간에도 DB의 정보 수집이 가능하다는 점일 것이다. 단점은 많은 정보가 추출되고, Text 기반으로 출력 형식이 정해져 있어서 보고자 하는 정보를 찾거나 보기가 불편하다는 점일 것이다.

반면, db2top은 (v9.5부터 제품 설치 시 제공되어짐, 하위 버전의 경우는 최신 fixpack에 포함되어제공됨)  snapshot 함수를 이용한 방식으로 telnet 등의 서버 레벨에서 정보를 보기 편하게 제공한다. (linux의 top이나 aix의 topas 같은 Text 기반 GUI ?)

단점은 DB 서버에 부하가 심하거나 하는 경우 수집이 잘 되어지지 않는다. DB에  접속을 해서 정보를 수집하기에 “성능 부하” 문제로 정보를 모니터링 하기에는 조금 힘든 면이 있다. Text 기반으로 정보를 보여주어도 보기 편하게 제공을 하기 때문에 편의성은 좋다고 할 수 있겠다.

이 중 db2top을 이용하여 실행 중인 SQL을 확인해 보는 방법을 살펴보고자 한다.

DB2 서버에 telnet 으로 접속(db2 사용자 계정) 을 하여 수행한다. (DB명: sample)

명령어
> db2top –d sample

대문자 D키를 누르고,

대문자 L 키를 눌러 보고자 하는 SQL의 Hash Value 입력

실행 중인 SQL 전체 구문을 얻을 수 있다. Dynamic SQL 경우에는 (jsp 등에서 ? 처리해서 동적 변수가 실행되는 SQL) 변수 값이 ?로 처리되서 들어오는 문제점은 있다.

db2pd를 통해서 SQL을 확인한다면

> db2pd –d sample –dynamic

Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:06:46 -- Date 03/12/2012 13:17:07

Dynamic Cache:
Current Memory Used           912084
Total Heap Size               1271398
Cache Overflow Flag           0
Number of References          184
Number of Statement Inserts   26
Number of Statement Deletes   8
Number of Variation Inserts   18
Number of Statements          18

Dynamic SQL Statements:
Address            AnchID StmtUID    NumEnv     NumVar     NumRef     NumExe     Text
0x00002B8015F1FD60 111    1          1          1          1          1          SELECT POLICY FROM
    SYSTOOLS.POLICY WHERE MED='DB2TableMaintenanceMED' AND DECISION='TableRunstatsDecision' AND NAME='TableRunstatsPolicy'
0x00002B8015E4F440 164    1          1          1          3          3          SELECT COLNAME, TYPENAME FROM
     SYSCAT.COLUMNS WHERE TABNAME='POLICY' AND TABSCHEMA='SYSTOOLS'
0x00002B8015F2CB80 167    1          1          1          1          1          SELECT IBM.TID, IBM.FID FROM
    SYSIBM.SYSTABLES AS IBM, SYSTOOLS.HMON_ATM_INFO AS ATM WHERE ATM.STATS_FLAG <> 'Y' AND IBM.TYPE IN ( 'S', 'T' ) AND
    ATM.CREATE_TIME = IBM.CTIME AND ATM.SCHEMA = IBM.CREATOR AND ATM.NAME = IBM.NAME ORDER BY IBM.FID, IBM.TID WITH UR
0x00002B8015E423C0 185    1          1          1          1          1          select * from emp
0x00002B8015F279A0 332    1          1          1          1          1          UPDATE SYSTOOLS.HMON_ATM_INFO
    AS ATM SET STATS_FLAG = 'N', REORG_FLAG = 'N' WHERE (ATM.SCHEMA, ATM.NAME) IN   (SELECT IBM.CREATOR,           IBM.NAME
    FROM SYSIBM.SYSTABLES AS IBM    WHERE IBM.TYPE = 'N' )
0x00002B8015EF7400 340    1          1          1          2          2          SELECT TABNAME FROM
    SYSCAT.TABLES  WHERE TABNAME='HMON_ATM_INFO' AND  TABSCHEMA='SYSTOOLS'
0x00002B8015E8CFE0 450    1          1          1          3          3          SELECT TRIGNAME FROM
    SYSCAT.TRIGGERS WHERE TABNAME='POLICY' AND TABSCHEMA='SYSTOOLS'
0x00002B8015F01E80 462    1          1          1          156        156        SELECT CREATE_TIME FROM
    SYSTOOLS.HMON_ATM_INFO WHERE SCHEMA = ? AND NAME = ? FOR UPDATE
0x00002B8015E469A0 513    1          1          1          1          1          select * from staff
0x00002B8015E4B640 580    1          1          1          3          3          CALL
    SYSPROC.SYSINSTALLOBJECTS('POLICY','V','','')
0x00002B8015F1B4E0 639    1          1          1          1          1          DELETE FROM
    SYSTOOLS.HMON_ATM_INFO AS ATM WHERE NOT EXISTS ( SELECT * FROM SYSIBM.SYSTABLES AS IBM WHERE ATM.NAME = IBM.NAME AND
    ATM.SCHEMA = IBM.CREATOR AND ATM.CREATE_TIME = IBM.CTIME ) WITH UR
0x00002B8015F23D80 734    1          1          1          1          1          UPDATE SYSTOOLS.HMON_ATM_INFO
    AS ATM SET ATM.STATS_FLAG = 'Y'
0x00002B8015E91DC0 735    1          1          1          2          2          CALL SYSINSTALLOBJECTS(
    'DB2AC', 'V', NULL, NULL )
0x00002B8015F016E0 766    1          1          1          1          1          SELECT CREATOR, NAME, CTIME
    FROM SYSIBM.SYSTABLES WHERE TYPE='T' OR TYPE='S' OR TYPE='N' WITH UR
0x00002B8015E91160 809    1          1          1          3          3          SET CURRENT LOCK TIMEOUT 5
0x00002B8015EFF380 876    1          1          1          1          1          UPDATE SYSTOOLS.HMON_ATM_INFO
    SET STATS_LOCK = 'N', REORG_LOCK = 'N'
0x00002B8015EFB680 886    1          1          1          2          2          SELECT TABNAME FROM
    SYSCAT.TABLES  WHERE TABNAME='HMON_COLLECTION' AND  TABSCHEMA='SYSTOOLS'
0x00002B8015F2EF00 1014   1          1          1          1          1          SELECT POLICY FROM
    SYSTOOLS.POLICY WHERE MED='DB2CommonMED' AND DECISION='NOP' AND NAME='CommonPolicy'

Dynamic SQL Environments:
Address            AnchID StmtUID    EnvID      Iso QOpt Blk
0x00002B8015F1FF20 111    1          1          CS  5    B
0x00002B8015E4F5C0 164    1          1          CS  5    B
0x00002B8015F2CDA0 167    1          1          CS  5    B
0x00002B8015E42500 185    1          1          CS  5    B
0x00002B8015F27BA0 332    1          1          CS  5    B
0x00002B8015EF7580 340    1          1          CS  5    B
0x00002B8015E8D160 450    1          1          CS  5    B
0x00002B8015F174A0 462    1          1          CS  5    B
0x00002B8015E46AE0 513    1          1          CS  5    B
0x00002B8015E4B7A0 580    1          1          CS  5    B
0x00002B8015F1B6C0 639    1          1          CS  5    B
0x00002B8015F23EE0 734    1          1          CS  5    B
0x00002B8015EF3CA0 735    1          1          CS  5    B
0x00002B8015F01860 766    1          1          CS  5    B
0x00002B8015E912A0 809    1          1          CS  5    B
0x00002B8015EFF4E0 876    1          1          CS  5    B
0x00002B8015EFB800 886    1          1          CS  5    B
0x00002B8015F2F080 1014   1          1          CS  5    B

Dynamic SQL Variations:
Address            AnchID StmtUID    EnvID      VarID      NumRef     Typ Lockname                   Val Insert Time                Sect Size

DAS 에 대한 블로그 글에 Windows 작업 스케줄러에서 DB2 자동화 방법에 대한 문의가 있었다. 최근 Windows 용 DB2를 설치했던 고객사에서도 관련하여 문의가 왔었다. 인터넷에서 관련 자료 검색이 잘 안되었나 하는 생각이 들기도 하여 블로그에 남겨 본다.

Windows XP에서 작업 스케줄러를 설정하는 것과 Windows 7 혹은 Vista 혹은 2008 Server에서 설정하는 방법이 약간 다르다.

DB2 관련 작업을 자동화하기 위해 개인적으로 2개의 파일을 만들어서 설정을 했다.

### XP  및 Windows 2003 서버의 경우 ####

1. cmd 파일 (파일명 예:  backup.cmd)

db2cmd /w /c /i db2 -tf backup.sql >> bak.txt

작업 스케줄러에서  backup.cmd 파일을 등록해서 실행시키면 된다.

실행여부는 bak.txt 로그 파일을 통해 수행 여부를 확인하면 된다.

 

2. db2 파일 (파일명 예: backup.db2)

    파일 확장자는 임의적이다.

!db2 "connect to sample" ;

!db2 "quiesce db immediate force connections" ;

!db2 "terminate" ;

!db2 "backup db sample to 'C:\'" ;

!db2 "connect to sample" ;

!db2 "unquiesce db" ;

!db2 "terminate" ;

위 명령어는 Offline Backup을 받기 위해서 DB에 접속된 연결을 강제 제거하여 DB를 비활성화(offline)시킨 후 백업을 수행하도록 쓰여졌다. (! 는 OS 레벨에서 수행되도록 하기 위한 DB2 환경에서의 escape 문자이다)

 

### Vista 이상  및 Windows 2008 서버의 경우 ####

작업 스케줄러 등록 방식이 바뀌었다.

시작 > 관리도구 > 작업 스케줄러 > 작업만들기 (창의 오른쪽 패널의 “작업”에 “작업 만들기” 선택)

* 동작 Tab  > 새로만들기

   - 프로그램/스크립트

“C:\Program Files (x86)\IBM\SQLLIB\BIN\db2cmd.exe

   - 인수 추가

db2 –tvf listdb1.db2

listdb1.db2 Script
!db2 "list db directory" >> db2list1.txt ;

   - 시작 위치   : listdb1.db2 위치

IBM에서는 V9.5부터 DB2_COMPATIBILITY_VECTOR 라는 레지스트리 변수를 통하여 ORACLE의 특수 기능을 동일하게 사용하도록 지원하기 시작하였다.

ORACLE에서 DB2로 object들을 변환 작업할 때, 도움이 많이 되지만 DBMS가 다른 만큼 동일하게 작용하지 않는 부분이 존재한다. 개인적으로는 “오라클 호환성” 기능은 ORACLE 적인 SQL 등을 내부적으로 DB2 기능으로 mapping 혹은 변환시켜주는 기능이지 “Oracle SQL”을 직접 수행하는 기능은 아니라고 생각하고 있다.

보통은 DB2 V9.7에서 오라클 호환성을 사용하기 위해서는 레지스트리 변수를 DB2_COMPATIBILITY_VECTOR=ORA 로 설정을 한 후 DB를 생성하도록 안내를 한다. 면밀하게 살펴보지는 않았으나 ORACLE의 시스템 관리 뷰들의 생성 유무 차이가 있다.

일반적인 기능은 DB 생성 후에도 “오라클 호환성 변수”를 적용해도 (db2 restart는 필요함) 되는 것으로 알려져 있는데, 다음과 같이 “미묘한 차이”가 발생을 한다.

1. 오라클 호환성을 적용한 후 DB 생성한 경우

테이블 생성
> db2 "create table t1(c1 date, c2 timestamp)"

테이블 DDL 생성
> db2look -d test -e -z "INST97" -t "T1"

결과 확인

CREATE TABLE "INST97 "."T1" (

"C1" TIMESTAMP(0) ,

"C2" TIMESTAMP )

IN "USERSPACE1" ;

테이블 삭제

db2 drop table t1

 

오라클 호환성 제거

db2set DB2_COMPATIBILITY_VECTOR=

db2stop

db2start

 

테이블 생성

db2 "create table t1(c1 date, c2 timestamp)"

 

테이블 DDL문 생성

db2look -d test -e -z "INST97" -t "T1"

 

결과 확인

CREATE TABLE "INST97 "."T1" (

"C1" TIMESTAMP(0) ,

"C2" TIMESTAMP )

IN "USERSPACE1" ;

db2 "select * from t1"

C1                           C2

-------------------  --------------------------

2011-10-26-16.47.38   2011-10-26-16.47.38.548792

  테스트 결과에서 보듯이, date 값이 timestamp(0) 으로 변환됨을 알 수 있다.

반면, 오라클 호환성을 적용하지 않고 DB를 생성한 경우 date 컬럼 속성은 변경되지 않았다.

 

2. 오라클 호환성을 적용하지 않고 DB 생성 후 오라클 호환성 적용한 경우

오라클 호환성 적용
db2set DB2_COMPATIBILITY_VECTOR=ORA

db2stop
db2start

테이블 생성
db2 "create table t1(c1 date, c2 timestamp)"

테이블 DDL 생성
db2look -d test -e -z "INST97" -t "T1"

CREATE TABLE "INST97 "."T1" (

"C1" DATE ,

"C2" TIMESTAMP )

IN "IBMDB2SAMPLEREL" ;


데이터 값 조회
db2 "select * from t1"

C1              C2

----------   --------------------------

2011-10-26   2011-10-26-16.57.49.963273

오라클 호환성을 적용하지 않고 DB 생성한 후에는 오라클 호환성 적용과 상관없이 date 형변환은 발생하지 않았다.

만일, 오라클 호환성을 DB를 생성한 상태에서 date 컬럼의 형 변환 막을 방법은 없을 것 같다. 다만 Application에서 값을 가공 처리할 수는 있을 것 같다.

개인적으로는 오라클 호환성을 적용한 경우, SQL 해석기를 DB2로 할 것인지, Oracle로 할 것인지 사용자가 선택할 수 있는 장치가 마련되어야 하지 않은가 하는 생각이 든다.

IBM 기술지원센터에 문의를 해 보지 않아서 bug 여부는 확인하지 않았다.

DB2에서 백업은 데이터베이스 범위에서 이뤄진다. DB보다 큰 범위인 인스턴스 범위에서의 백업은 db2 get dbm cfg 나 db2set –all 등을 통해서 백업받는게 보통인데, 버전이 올라갈 수록 DB 윗단의 백업으로서 사용할만 해지는 것 같다.(추출되어지는 정보가 많아짐)

1. db2rspgn

DB2 식 용어로는 “응답 설치” 방법으로 일컬어지면서 등장하는 “응답파일 생성 도구”이다. “응답 파일 설치는” 쉽게 말해 “묻지마 설치”라고 표현할 수 있을 것 같다. 위 명령어를 사용하면 DB2 설치에서 OS 계정 생성, DB2 설정, DB 생성까지 일괄 실행할 수 있는 파일이 생성된다.

(많진지 오래되서 기억이 가물해졌지만) oracle도 인스턴스 및 DB 생성 시 “설정 파일”을 이용해서 생성하는 법이 있었던 것 같은데 그것과 비슷하다고 하지 않을까 싶다.

설치에 필요한 모든 정보들 파일에 담아 놓고, “어떻게 설정해 놓느냐”에 따라 한번의 실행으로 더이상 손댈 필요없이 설치 작업이 진행된다.

이런 설치는 보통 HADR이나 DPF구성 시, 여러 머신에 동일하게 설치할 때 사용하면 좋지 않을까 싶다.

명령어

db2rspgn –d 생성경로 –i 인스턴스명

위 명령어를 수행하면 2개의 파일이 생성된다. (rsp 파일, ins 파일)

DB 생성 및 설정작업 후 응답 파일을 생성하면 이와 관련한 설정값도 다 추출되서 응답 파일이 저장된다.

 

설치 명령어

설치이미지/db2setup –r 응답파일경로/응답파일.rsp

PoC나 BMT 작업으로 여러 대 설치를 해야될 일이 있어서 활용을 해 보았는데, 약간 불편한 사항이 있어서 계속 써지지는 않았다.

추출 후, rsp 파일에서 “계정 비밀번호 설정” 과 라이센스 조항 “승인” 설정을 해 주어야 한다.

이외 별도의 파일시스템(디렉토리 및 파티션)에 사용자 계정이나 DB를 생성한 경우, 그 접근할 수 있도록 사전에 소유권 변경작업이 필요하다.

 

2. db2cfexp

db2repgn의 작업은 db2cfexp 도구와 겹치는 부분이 존재한다.

configuration 을 export하는 도구로서 수행 시 db2set 과 dbm cfg 변수값들이 추출되어 저장된다.

추출 옵션이 3가지 (backup, maintain, template) 존재하지만 backup을 덮어놓고 쓰는 편이다.

 

명령어

db2cfexp 백업파일명 backup

백업파일명은 임의적이고, 실행 위치에 파일이 생성된다.(인스턴스 계정으로 수행)

관리 용으로 설정(profile)작업을 백업받는 용도로 사용할 수도 있지만, db2 fixpack 적용 시 백업 후,인스턴스 업데이트 후 설정 값을 다시 적용하고자 할 때 사용할 수 있겠다.

 

적용

db2cfimp 백업파일명

위 함수는 V9.7 FixPack4에서 새롭게 소개된 함수이다. 특정 컬럼 기준으로 그룹의 문자열 값 세트를 하나의 문자열로 집계하도록 하는 기능을 한다.

고객사쪽에서 문의가 와서 고민하다 위 함수가 생각이 나서 소개를 해 주었는데, 나름 의미가 있을 듯 해서 블로그에도 남겨 본다.

저장된 데이터

C1          C2          C3
----------- ----------- ---
          1           1 A
          1           1 B
          1           1 C
          1           2 D
          1           3 E

 

원하는 결과값

C1          C2          C3_SUM
----------- ----------- ------------
          1           1 A,B,C
          1           2 D
          1           3 E

 

LISTAPP() 함수를 쓰면 다음과 같이 간단한 SQL로 구현된다.

select c1,
         c2,
         substr(listagg(c3,',') within group(order by c3),1,12) as c3_sum
from t1
group by c1, c2

결과값

C1          C2          C3_SUM
----------- ----------- ------------
          1           1 A,B,C
          1           2 D
          1           3 E

 

만일 V9.7 FixPack4 미만이라 사용할 수 없는 경우라면?

본 SQL 경우에는 3개의 문자를 붙이는 경우가 최대라고 가정하고 구현된 SQL이다. Stored Procedure 나 사용자 함수(UDF)를 만들어서 구현한다면 조금은 간단한 SQL 되지 않을까 싶다.

select a.c1, a.c2, a.c5||','|| b.c3 c3
from t1 b,
(select a.c1, a.c2, a.c3, t1.c3 c4, a.c3 || ',' || t1.c3 c5
from t1,
    (select a.c1, a.c2, b.c3
           from (select c1,c2,count(c3) cnt from t1 group by c1, c2 having count(c3) > 1 ) a,
                (select c1,c2,c3 from t1)b
     where a.c1=b.c1 and a.c2=b.c2 fetch first 1 rows only) a
where a.c1 = t1.c1 and a.c2 = t1.c2 and a.c3 <> t1.c3  fetch first 1 rows only) a
where a.c1=b.c1 and a.c2=b.c2 and b.c3 <> a.c3 and b.c3 <> a.c4

union all

select c1, c2, max(c3) c3 from t1 group by c1,c2 having count(c3) = 1

결과값

C1          C2          C3
----------- ----------- -----------
          1           2 D
          1           3 E
          1           1 A,B,C

  3 record(s) selected.

 

테스트한 table 및 insert 문

db2 "create table t1 (c1 integer, c2 integer, c3 varchar(3))"
db2 "insert into t1 values (1,1,'A'),(1,1,'B'),(1,1,'C'),(1,2,'D'),(1,3,'E')"

대부분의 DBMS는 메모리 영역을 3가지로 분류를 한다.

DB2 입장에서는 인스턴스 영역, 데이터베이스 영역, Application 영역 식으로 표현할 수 있겠지만, 다른 DBMS인 경우는 다르게 표현될 것이다.

DBM CFG 및 DB CFG의 메모리 설정 값은 총 값(인스턴스 메모리가 DB 공유메모리를 포함함)을  의미하지만, 모니터링을 통한 각 값은 분리되어 확인이 된다.

V8.x 에서는 db2mtrk를 통하여 확인을 할 수 있었지만, V9.x 부터는 뷰(snapdbm_memory_pool 등)를 통해서 확인할 수 있다.

인스턴스 사용 메모리 크기

명령어

db2 “db2mtrk -i –v”                 

결과

Tracking Memory on: 2011/12/26 at 15:35:25

Memory for instance

   Other Memory is of size 30212096 bytes
   FCMBP Heap is of size 15859712 bytes
   Database Monitor Heap is of size 327680 bytes
   Total: 46399488 bytes


명령어

db2 +p –tv << EOF

select pool_id, sum(pool_cur_size) instance_mem_tsize
from sysibmadm.snapdbm_memory_pool
group by grouping sets(pool_id,())
with ur;

EOF

결과

POOL_ID        INSTANCE_MEM_TSIZE 
-------------- --------------------
-                          21561344
FCMBP                        851968
MONITOR                      327680
OTHER                      20381696

 

데이터베이스 메모리 크기

명령어
db2 “db2mtrk -d –v”

결과

Memory for database: SAMPLE

   Backup/Restore/Util Heap is of size 65536 bytes
   Package Cache is of size 786432 bytes
   Other Memory is of size 196608 bytes
   Catalog Cache Heap is of size 393216 bytes
   Buffer Pool Heap (1) is of size 8650752 bytes
   Buffer Pool Heap (System 32k buffer pool) is of size 851968 bytes
   Buffer Pool Heap (System 16k buffer pool) is of size 589824 bytes
   Buffer Pool Heap (System 8k buffer pool) is of size 458752 bytes
   Buffer Pool Heap (System 4k buffer pool) is of size 393216 bytes
   Shared Sort Heap is of size 0 bytes
   Lock Manager Heap is of size 17629184 bytes
   Database Heap is of size 19791872 bytes
   Application Heap (13) is of size 65536 bytes
   Application Heap (12) is of size 65536 bytes
   Application Heap (11) is of size 196608 bytes
   Application Heap (10) is of size 65536 bytes
   Application Heap (9) is of size 65536 bytes
   Application Heap (8) is of size 65536 bytes
   Application Heap (7) is of size 65536 bytes
   Applications Shared Heap is of size 458752 bytes
   Total: 50855936 bytes


명령어
db2 +p –tv << EOF

select substr(db_name,1,8) dbname,
       pool_id,
       sum(pool_cur_size) db_mem_tsize
from sysibmadm.snapdb_memory_pool
group by grouping sets(db_name, pool_id)
with ur;
EOF

 

Application & Private 사용 메모리 크기

명령어
db2 “db2mtrk –a –p  –v”

결과

Application Memory for database: SAMPLE

   Applications Shared Heap is of size 524288 bytes
   Total: 524288 bytes

  Memory for application 13

   Application Heap is of size 65536 bytes
   Other Memory is of size 196608 bytes
   Total: 262144 bytes

  Memory for application 12

   ……………

Memory for agent 33

   Other Memory is of size 196608 bytes
   Total: 196608 bytes

Memory for agent 32

   Other Memory is of size 196608 bytes
   Total: 196608 bytes

    ………………


명령어
db2 +p –tv << EOF

select substr(db_name,1,8) dbname, pool_id, sum(pool_cur_size) app_mem_tsize
from sysibmadm.snapagent_memory_pool
group by grouping sets(db_name,pool_id)
with ur
;

EOF

DBMS마다 데이터베이스가 가지는 자원들은 차이가 난다.

ORACLE 경우는 인스턴스와 DB가 붙어있어서 자원 구분이 불분명하지만, DB2의 경우는 DB 하위에 독립적인 트랜잭션 로그, 메모리(버퍼풀), 테이블 공간등을 지정하고 관리를 한다.

Informix의 경우는 인스턴스 범위에서 트랜잭션 로그, 시스템(메타 테이블) 정보, DB 공간이 지정되고 관리가 된다. (어렴풋한 기억을 더듬어 보면 MS-SQL, Sybase 는 informix와 비슷하지 않을까 싶다.)

그 아키텍처가 제조사 별로 다르기 때문에 DB 크기 산정도 차이가 나겠지만, 그 기준이 되는 것은 “테이블 공간”들의 합일 것이다.

DB2에서는 프로시저를 실행함으로서 DB의 사용크기와 가용 크기를 확인할 수 있다. (단위는  byte)

명령어
        db2 “call sysproc.get_dbsize_info(?,?,?,-1)

참고

    - 첫번째 출력 변수: 실행된 시간소 값

    - 두번째 출력 변수: 데이터베이스의 크기

      (산정방식: dbsize = sum (used_pages * page_size) for each table space (SMS & DMS))

    - 세번째 출력 변수: 데이터베이스 가용 크기

      (산정방식: dbcapacity = SUM (DMS usable_pages * page size) + SUM (SMS container size + file system free size per container))

    - 네번째 입력 변수: 수집 시간 간격 (기본 값: –1)

     -1인 경우 30분 단위 수집을 의미하며, 입력 값은 “분” 단위임

 

 

실행 결과

출력 매개변수 값
--------------------------
매개변수 이름  : SNAPSHOTTIMESTAMP
매개변수 값 : 2004-02-29-18.33.34.561000

매개변수 이름  : DATABASESIZE
매개변수 값 : 22302720

매개변수 이름   : DATABASECAPACITY
매개변수 값 : 4684859392

리턴 상태 = 0

 

간단한 방법은 db2top을 통하여 확인할 수 있다.(옵션: t)

 

화면 아래 가운데 DB Size가 명시되어 있다. (현 크기/ 가용 크기)

KDUG를 방문했다가 oracle “connect by” 변환에 대한 질문이 있어 테스트를 해 보았다.

댓글 달기가 좀 불편한 점이 있어 recursive 처리에 대한 자세한 내용을 하지 못해서, 이곳에 좀 더 자세히 올리면 좋겠다 하는 생각에 적어 본다.

V9.1까지는 오라클 SQL 호환성 기능이 지원되지 않아 recursive 처리가 쉽지가 않았다. 9.5부터 connect by 사용이 가능해져서 전보다 변환 작업이 편해 졌을 것이라 생각한다.

참고로 오라클 SQL 호환성 기능을 활용하여 ORACLE 변환 작업한 기회가 많지 않아 어느 정도 가능한지 말하기는 어렵다. (단, 2년 전 V9.7 Cobra로 PoC 수행시 문제가 발생해서 connect by를 쓰지 않고 Common table로 변환 처리했던 기억이 어렴풋이 난다. ^^; )

테스트는 sample 데이터베이스의 department 테이블로 한다.

1. department 테이블 정의

$ db2 describe table department

Column name                            schema    Data type name      Length     Scale Nulls
------------------------------- --------- ------------------- ---------- ----- ------
DEPTNO                                    SYSIBM    CHARACTER                    3          0 No
DEPTNAME                               SYSIBM    VARCHAR                       36          0 No
MGRNO                                    SYSIBM    CHARACTER                    6           0 Yes
ADMRDEPT                               SYSIBM    CHARACTER                    3           0 No
LOCATION                                SYSIBM     CHARACTER                   16          0 Yes

deptno 컬럼의 값과 admrdept 컬럼의 값이 동일하다. 이 2 컬럼을 통하여 “계층"(hierarchey) 처리가 가능하다.

 

2. department 데이터

$ db2 "select deptno, admrdept from department"

DEPTNO ADMRDEPT
------ --------
A00    A00
B01    A00
C01    A00
D01    A00
D11    D01
D21    D01
E01    A00
E11    E01
E21    E01
F22    E01
G22    E01
H22    E01
I22     E01
J22    E01

  14 record(s) selected..

 

3. 계층  recurcive 처리

   (1) deptno 컬럼과 admrdept 컬럼의 값이 동일한 값을 “최상위 계층”이라 정의하고 level에 0 값을 지정하여 parent 테이블에 저장한다. (아래 SQL의 붉은색 글씨)

    (2) “최상위 계층”의 값의 deptno값과 department 테이블의 admrdept 값이 일치하는 값을 찾아

두번째 level의 데이터를 찾아 parent 테이블에 저장한다. (연두색 글씨)

    (3) 두번째 level 값을 갖는 deptno 값을 통하여 department 테이블의 admrdept 값이 일치하는 값을 다시 찾아 세번째 level 데이터를 parent 테이블에 저장한다.

    (4) 이렇게 parent 테이블에 저장된 데이터를 통하여 새로운 level의 데이터를 찾은 후, 전체 데이터에 대해 완료하면 parent 테이블을 조회하여 값은 반환시킨다.

(a.deptno != p.fkey 에 대한 이유는 글을 보시는 분들에게 숙제로 남겨 본다.)

$ db2 +p -tv << EOF

> with parent (pkey, fkey, level) as
> (select deptno, admrdept, 0 from department
where deptno = admrdept
>    union all
select a.deptno, a.admrdept, p.level+1
from department a, parent p
where a.deptno != p.fkey and a.admrdept = p.pkey
> )
> select p.pkey,p.level from parent as p;
> EOF
with parent (pkey, fkey, level) as (select deptno, admrdept, 0 from department where deptno = admrdept union all select a.deptno, a.admrdept, p.level+1 from department a, parent p where a.deptno != p.fkey and a.admrdept = p.pkey ) select p.pkey,p.level from parent as p

PKEY        LEVEL
----          -----------
SQL0347W  The recursive common table expression "INST97.PARENT" may contain an
infinite loop.  SQLSTATE=01605

A00            0
B01            1
C01            1
D01            1
E01            1
D11            2
D21            2
E11            2
E21            2
F22            2
G22            2
H22            2
I22            2
J22            2

  14 record(s) selected with 1 warning messages printed.

 

4. recursive가 되는 테이블의 SELECT 절에 recursive 처리는 넣어 처리하려면?

이것은 KDUG에 문의된 내용이다. 될까? 안될까? 궁금해서 테스트를 해 보았는데 한 SQL에서 recursive를 2번 사용하는 것은 지원되지 않는 듯 하다. (SQL0104N 에러 발생)

그래서 SELECT 절에서 사용되는 recursive 처리는 UDF (User define Function)으로 빼서 처리를 했더니 이중 recursive 처리가 되었다.

with parent (pkey, fkey, level) as
(select deptno, admrdept, 0 from department
where deptno = admrdept
union all
  select a.deptno, a.admrdept, p.level+1
  from department a, parent p
  where a.deptno != p.fkey and a.admrdept = p.pkey
)

select p.pkey,p.level,
       ( with subpar (pkey,fkey, level) as
           ( select d.deptno, d.admrdept, p.level from department d where d.admrdept=p.pkey
              union all
              select a.deptno, a.admrdept, s.level+1 from department a, subpar s where a.deptno !=s.fkey and a.admrdept=s.pkey
            )
         select count(*) from subpar) as subcnt
from parent as p;

 

실행 결과

SQL0104N  An unexpected token "as" was found following "r (pkey,fkey, level)".

Expected tokens may include:  "JOIN".  SQLSTATE=42601

 

SELECT 절의 recursive의 함수 처리

db2 +p -td"@" -v << EOF
drop function reccnt() @
create function reccnt(p_key varchar(5), p_level integer)
returns integer
return with subpar (pkey,fkey, level) as
            ( select d.deptno, d.admrdept, p_level from department d where d.admrdept=p_key
              union all
              select a.deptno, a.admrdept, s.level+1 from department a, subpar s where a.deptno !=s.fkey and a.admrdept=s.pkey
            )
         select count(*) from subpar
@
EOF


SQL0347W  The recursive common table expression "INST97.SUBPAR" may contain an
infinite loop.  SQLSTATE=01605

 

Recursive SQL

db2 +p -tv << EOF
with parent (pkey, fkey, level) as
(select deptno, admrdept, 0 from department
where deptno = admrdept
union all
  select a.deptno, a.admrdept, p.level+1
  from department a, parent p
  where a.deptno != p.fkey and a.admrdept = p.pkey
)
select pkey,level, reccnt(pkey, level) as cnt from parent;
EOF

실행 결과

PKEY        LEVEL       CNT
----         ----------- -----------
SQL0347W  The recursive common table expression "INST97.SUBPAR" may contain an
infinite loop.  SQLSTATE=01605

A00            0          27
B01            1           0
C01            1           0
D01            1           2
E01            1           7
D11            2           0
D21            2           0
E11            2           0
E21            2           0
F22            2           0
G22            2           0
H22            2           0
I22             2           0
J22            2           0

  14 record(s) selected with 1 warning messages printed.

Recursive 처리 구현이 어느 정도는 가능하지만, 데이터가 많은 경우 성능 저하는 심하게 발생할 수 밖에 없다. Connect by를 이용한 처리에 비해 부하가 더 심할지, 비슷한지는 비교해 본 적이 없기에 알 수 없지만 “꺼려지는 SQL” 이다.

+ Recent posts