728x90

nohup


부모프로세스가 죽어도 계속 자식프로세스가 돌아감 ( cf : & )


보통 사용자가 로그인해서 여러 백그라운드 작업을 만들게 되는데 이때 백그라운드도 작업이 진행되고 있는 도중에 사용자가 로그아웃을 하면 진행 중이던 백그라운드 작업도 중단된다. 이유는 이러한 모든 백그라운드 프로세스는 사용자의 로그인 쉘에서 만들어진 자식 프로세스들이기 때문이다. 그러나 유닉스 시스템은 로그아웃하여도 백그라운드 프로세스는 계속 진행되도록 할 수 있는 명령어를 제공하고 있다.

CPU 시간을 많이 소요하는 프로세스는 이렇게 백그라운드 작업으로 진행시킴으로써 사용자들이 거의 시스템을 사용하지 않는 시간에 자신의 작업을 진행시킬 수 있다. nohup(no hang up) 명령어는 이러한 목적을 위해 사용되며, 그 형식은 다음과 같다.


% nohup 명령어 &


위 명령은 사용자가 로그아웃하는 것과 무관하게 지정해 준 작업이 모두 종료될 때까지 진행시키라는 의미이다. nohup 명령어는 일반적으로 백그라운드 작업에 사용되는데, 그렇지 않으면 프롬프트가 화면에 나타나지 않으므로 로그아웃할 수 있는 방법이 없기 때문이다. 또한, nohup상태에서 백그라운드로 작업을 수행토록 한 후, logout하였다가 다시 로그인하여 계속 중인 백그라운드 작업을 중지시킬 수 없다. 하지만 logout하지 않은 상태라면 ‘kill 프로세스번호’를 수행하여 작업을 중지시킬 수 있다.


예를 들어, 어느 anonymous ftp 사이트에서 비교적 용량이 큰 파일을 다운로드하는 경우, 트래픽의 폭주로 인하여 다운 받는 시간이 장시간 걸린다면, 다운 받는 동안 구태여 컴퓨터를 켜 놓지 않고 백그라운로 작업을 지시하는 것이 좋다.

그러므로 작업지시 명령어에는 자신이 ftp 사이트에 접속해서 행하는 명령어를 그대로 기록해 두어야 한다.

아래의 예제를 위해 radiocom.kunsan.ac.kr/pub/win에 있는 abc.exe라는 파일을 가져온다고 가정하고, 먼저 vi 편집기로 ftp에서 행하는 명령어를 그대로 작성한다.



예제】

% vi sample


ftp -n radiocom.kunsan.ac.kr << EOF

user anonymous jijoe@ks.kunsan.ac.kr

cd /pub/win

bi

get abc.exe

bye

EOF


% chmod 700 sample

% nohup sample &

% jobs

[1]  + Running  sample

% logout

% cat nohup.out   ☜ 다시 로그인해서



위 예제에서 vi 편집기로 작성된 문서를 먼저 실행모드로 바꾸기 위해서 “chmod 700”를 실시하였다. 여기서 jobs는 현재 프로그램이 정상적으로 잘 작동되고 있는지 여부를 확인하기 위해서 입력한 명령어에 불과하다. “Running sample”이라는 메시지를 보니 정상 작동되고 있음을 알 수 있으므로 이제 logout하더라도 유닉스 시스템이 원하는 파일을 다운 받아 놓는다.


nohup 명령을 이용하여 어떤 작업을 백그라운드(&)로 실행시키면, 그 진행과정은 모두 nohup.out 파일에 기록되기 때문에 차후에 진행과정을 확인하는데 유용하게 사용된다.


출처 : http://radiocom.kunsan.ac.kr

728x90

'*nix' 카테고리의 다른 글

sed 사용법  (0) 2010.06.01
vi 특정문자열 삭제  (0) 2010.06.01
로그파일 가공하기  (0) 2010.05.17
awk 사용법  (0) 2010.05.17
[AIX] 한글 로케일  (0) 2010.01.20
728x90

아카이브(Archive)

l        향후 엑세스될 필요가 있는 정보의 1차 소스

l        운영환경으로부터 고정 콘텐츠 또는 비정형데이터를 추출함으로써 운용 효율성 향상

l        장기간 보존

l        엔터프라이즈 아카이브는 대량의 오브젝트를 축적

l        정보의 보관주기 및 폐기 등을 위한 어플리케이션 및 비즈니스 정책이 고려되어야 함



백업(Backup)

l        복구 목적으로 사용되는 2차 사본

l        장애시 어플리케이션이 특정시점으로 복구될 수 있도록 함으로써 가용성 향상

l        단기간 보존

l        주기적인 데이터 덮어쓰기

l        정책적인 요구사항이 거의 없음



(출처 : 효성인포메이션시스템(주)Next Generation Content Archiving Solution Seminar, 2006년 5월 17일)

728x90

'용어' 카테고리의 다른 글

DBMS의 종류  (0) 2010.01.04
OLE DB에 대한 이야기  (0) 2009.12.17
당신도 데이터베이스 관리자인가요?  (0) 2009.07.08
DBA란?  (0) 2009.07.08
아직도 UTF-8을 안 쓰십니까?  (0) 2009.07.08
728x90

Parallel DML은 기본적으로 session에 "enable" 되어 있지 않습니다. PDML과 serial DML의 locking, transaction, disk space requirement 등의 차이에 의해 PDML mode의 "enable"이 요구됩니다.

ALTER SESSION ENABLE PARALLEL DML;

따라서 Parallel DML이 "disable"되있을 경우 parallel hint나 table/index에 degree가 설정되어 있어도 이는 무시되게 됩니다. 물론 PDML mode가 "enable"되어 있어도 parallel hint나 table/index에 대한 degree가 설정되어 있어야 PDML로 수행 가능하다.


한 Transaction은 서로 다른 table에 대해 여러 PDML이 수행될 수 있습니다. 그러나 PDML로 변경된 table에 대해 해당 transaction 내에서 serial/parallel 명령(DML or Query)으로 access를 할 수 없습니다. 즉 commit/rollback 등으로 transaction을 완료 후에야 동일 table에 대한 operation이 가능합니다.
(참조 Note 201978.1 PDML Restrictions on Parallel DML)

Oracle 9i 이후에 intra-partition parallelism 개념이 소개되었습니다.
이 개념은 partition당 한개씩만 수행되는 parallel execution server의 제한을 완화(?) 시키는 개념입니다.
(참고 Note 241376.1 What is Intra-partition parallelism )

특정 세션의 PDML의 "enable" 여부는 v$session의 PDML_STATUS, PDDL_STATUS, PQ_STATUS column으로 확인 할 수 있습니다.

SQL> SELECT SID,PDML_STATUS, PDDL_STATUS, PQ_STATUS FROM V$SESSION;

SID PDML_STATUS PDDL_STATUS PQ_STATUS
---------- ------------ ------------ ------------
141 DISABLED DISABLED DISABLED
143 DISABLED ENABLED ENABLED
145 DISABLED ENABLED ENABLED
148 DISABLED ENABLED ENABLED
150 DISABLED DISABLED DISABLED

728x90
728x90

현장중계! 대한민국 개발자의 도전과 희망
1부, 기술 분야별 고민 해결 리포트

“당신도 데이터베이스 관리자인가요?”

고승훈 | 프로피아 오라클 기술팀장

데이터베이스를 처음 접하는 관리자가 갖는 막연한 두려움을 없애고 사소한 것이라도 원리에 충실한 지식만 있으면 어떠한 상황에서도 해결책이 있다는 것을 알려주기 위해서 이 글을 쓴다.

필자가 오라클을 접했을 때가 지난 1996년이었던 것으로 기억된다. 그때 버전은 7.0이었고 현재 버전이 10g로 변화하면서 Partitioning, Materialized View, Stream, Cache Fusion, Grid 등 새로운 기능 및 개념들이 많이 추가되었다. 
오라클을 처음 관리했을 때는 필자 역시 초보였고 뭐하나 작업을 하기 위해서는 명령문을 제대로 쓰고 있는가 하고 몇 번이고 망설이면서 사용했던 경험들이 많다. 필자의 초기 실수담을 하나 들자면 보통 오라클의 데이터베이스 파일의 확장자가 .dbf이다. 이전 파일 데이터베이스로는, dBASE IV들을 사용했던 경험자들은 알겠지만, 이것 역시 확장자가 dbf이다. 오라클을 몰랐던 필자는 오라클에서 사용했던 dbf 파일이 dBASE IV용 데이터 파일인 줄 알고 ftp로 전송을 시도했던 적이 있다. 물론 그날 전산실은 뒤집어졌음은 두말할 필요도 없다. 
필자의 생각에는 경험 없는 지식은 없다고 본다. 즉 머릿속으로만 기억하는 것은 지식으로써 의미가 반감된다는 것이다. 데이터 모델링, 재난 복구, 데이터베이스 운영 설계 등 생각만으로는 힘든 부분들이 많다. 특히 데이터 모델링 부분은 경험을 바탕으로 한 지식이 뒷받침되어야 한다. 이 글에서는 누구나 쉽게 이해할 수 있는 분야 중에서 재난 복구에 관한 필자의 경험을 통해 문제해결의 실마리를 푸는 각자의 열쇠를 찾기 바란다.

두 가지 순발력 테스트

글을 시작하기 전에 독자들에게 순발력과 관련된 상황문제를 제시해 보겠다. 5분이내로 정확하게 해답을 생각해내는 사람이라면 순발력이 좋다고 봐도 괜찮을 것이다.

“B지점의 입고량 좀 알고 싶소”

첫 번째 상황이다. 이것은 SQL문 작성에 관한 것인데 물류 쪽에서 가끔 나올 수 있는 질의다. 제품, 판매, 입고 등 3개의 테이블이 기본으로 주어지고 질의는 다음과 같다.

한 영업소 부장이 2004년 B지점에서 판매된 제품의 현재까지의 입고량을 보고 싶다고 갑자기 요청을 했다. 단순히 데이터만 보여주면 되었기 때문에 단순 조인으로 3개 테이블을 SELECT 작업을 했다. 그런데 이런! 결과가 10분이 지나도 나오지 않는 것이 아닌가? 당장 나온다고 큰소리 치고 시작했는데 10분이 지나고 20분이 지나도 나오지 않는 것이 아닌가? 등에선 땀이 나고 결국 30여분이 지나서야 결과가 나왔다. 그런데 이런 지점 코드가 B가 아니라 A라고 하면서 다시 결과를 보고 싶다고 한다. 이때 여러분은 어떻게 할 것인가? 또 다시 그대로 진행을 하여 30분 동안 기다릴 것인가?

답은 간단하다. 단순 조인 SQL문을 수정한 다음 질의를 하는 것이 낫지 않겠는가? 이제 질의문을 한 번 더 보자. 우리가 보고 싶은 것은 입고 현황이다. 즉 판매 쪽은 단지 판매가 된 제품코드를 얻기 위한 것이다. 그러므로 조금 더 생각을 하면 먼저 ‘2004년 A지점에서 팔린 제품 코드를 얻은 다음 이 코드를 가지고 입고량을 볼 수 있다’고 생각할 수도 있고, ‘2004년에 입고된 제품 중 2004년 A지점의 판매 내용에 있는지 여부를 체크한 다음에 있으면 입고량을 본다’라고도 해석할 수 있다. 이 두 가지의 경우에 따라 사용되는 SQL문이 달라진다. 처음에 제시한 내용에 대한 SQL문은 다음과 같이 나타낼 수 있다. 
<리스트 1>과 <리스트 2>는 서로 다르다. 그리고 맨 처음 생각했던 3개 테이블의 단순 조인과는 또 다르다. 결과는 단순 조인문과 <리스트 1>, <리스트 2>의 결과 값은 같다. 그러나 수행결과 시간에서 차이가 날 것이다. 왜 차이가 날까? 질의문 작성의 원칙은 ‘되도록이면 데이터를 줄여라’, 그리고 ‘필요 없는 조건수행을 하지 마라’이다. <리스트 1>은 데이터를 줄이는 부분에 충실한 것이고 <리스트 2>는 필요 없는 조건 수행을 없앤 것이다.

데이터베이스의 공간 할당

두 번째 상황은 데이터베이스 공간 할당이다. 여러분이 해결할 사항은 다음과 같다.

판매 입력을 배치 작업으로 진행하는 중에 갑자가 더 이상 EXTENTS를 증가할 수 없다는 메시지가 계속 나온다. 추가적으로 100MB짜리 데이터 파일을 추가했지만 같은 메시지가 계속 나온다. 오늘은 월말이고 내일 아침 판매회의 때 이달 말 판매 현황에 대한 보고서를 뽑기 위해서 영업부 직원들이 언제 작업을 할 수 있는지 물어보고 초보 데이터베이스 관리자였던 필자는 여러 방면으로 해결책을 찾아보고 있었다. 여러분들은 어떻게 할 것인가?

이 같은 문제는 데이터베이스 관리자가 겪는 에러 사항 중 가장 일반적인 문제라고 생각한다. 그런데 가끔 증가를 시켰는데도 문제가 계속적으로 발생하는 경우가 종종 있다. 요즘 버전에서도 가끔 일어나는데 우리가 아무 의미 없이 사용한 옵션 하나가 이러한 문제의 원인이다. 오라클에서는 ‘EXTENT는 연속된 공간의 세그먼트의 집합’이라고 한다. 이것을 기억하기 바란다. 예전에 필자가 겪었던 문제의 하나인데 디스크가 비쌌던 시절 ‘EXTENT 증가실패’ 메시지가 나와서 필자는 흔히 하는 방식대로 ‘ALTER TABLESPACE ADD .. ;’ 명령을 사용하여 증가를 시켰다. 사이즈는 100MB를 주었다. 그런데 동일 메시지가 발생을 했다. 이상하게도 전체적인 테이블스페이스 사용률도 70% 정도 밖에 안 되고 데이터 파일도 추가시켜 주었는데 발생을 했다. 여러분들은 어떤 측면으로 볼 것인가? 필자가 앞에서 했던 말 중 연속된 공간이라는 것을 떠올리면 답이 나올 수 있을 것이다. 그리고 EXTENT 증가시 그 크기를 어떻게 정하는지도 생각을 해라. 문제의 테이블 SALE이란 테이블의 PCTINCREASE 값이 기본 값인 50%로 되어 있었던 것이다. 그래서 EXTENT가 증가할 때마다 그전 크기의 50%만큼 계속 증가되어 최종적으로 약 80MB 정도가 마지막 EXTENT 크기가 된 것이다. 다음 EXTENTS의 크기는 ‘80+ 80*0.5= 120MB’가 되어서 새롭게 추가시킨 100MB로는 어림도 없었던 것이다. 그리고 전체 공간에서 30% 정도의 FREE 영역이 있다 해도 그것이 연속된 FREE 공간이라는 확신은 없다. 그래서 그 이후부터는 어떤 일이 있어도 PCTINCREASE 값은 0으로 설정한다. 
앞의 두 가지 상황에서 여러분들은 다른 선택을 했을지도 모른다. 그러나 문제를 어떤 방향으로 해석하느냐가 얼마나 중요한가를 느꼈을 것이며, 우리가 미처 인식하지 못했던 부분에서 나올 수도 있다는 사실이다. 항상 표면상의 문제뿐만 아니라 그 속에 숨어 있는 뜻을 알고자 하는 노력이 필요하다는 것을 필자는 두 가지 상황을 예로 들어 얘기하고 싶었던 것이고, 이제부터 필자가 쓰고자 하는 내용은 이러한 조그마한 지식이 어떻게 최악의 상황에서 필자를 구원했는지 이야기하려는 것이다.

최악의 상황은 예고 없이 찾아온다

지난 1999년쯤에 발생한 일이다. 필자는 전산실 데이터베이스 관리자로 근무하고 있었고, 그날은 일요일이어서 직접 회사 당직근무를 하고 있는데, 갑자기 영업부에서 회의 자료를 출력하는데 오류가 나온다는 것이다. 난 프로그램의 순간적인 오류로 생각하고 다시 시도해 보라고 한 다음에 전화를 끊었다. 그런데 이번엔 다른 영업부에서 전화가 왔다. 판매 자료가 조회 중에 갑자기 나오지 않는다는 것이다. 필자는 설마 데이터베이스가 어떻게 될 것이라고는 생각하지도 못한 상황에서 서버실로 들어가 보았다. 그 당시 필자의 회사는 다른 곳으로 이전하기 위해서 잠시 서버를 다른 곳에 옮겨둔 상태였기 때문에 서버 상태를 보기 위해서는 직접 그곳에 가야 했다. 서버실에 들어서니 상황이 생각했던 것보다 심각하다는 느낌을 받았다. 서버의 디스크에서는 소리가 ‘킥킥’하고 들렸던 것이다. 설마 디스크가? 그러나 이러한 필자의 생각은 적중했다. 디스크가 완전히 깨진 것이었다. 아침에 서버를 점검할 때에는 이상이 없었는데 한 시간도 안 지나서 디스크가 깨진 소리가 들린 것이었다.

백업은 당신의 수호천사

그 당시 필자의 회사는 백업 시스템이 제대로 갖추어지지 않았다. 데이터베이스 관리자로서 백업은 익스포트만 받았던 필자는 실제 물리적인 디스크에서 오류가 나자 복구할 수 있는 방법이 생각나지 않았다(그때 당시 왕 초보 관리자였음을 기억하기 바람). 만일 필자가 아카이브로 운영하고 있었고 백업 데이터 파일이 있었다면 아주 쉽게 복구한 다음 아무 일이 없었다는 듯이 무사히 당직근무를 마쳤을 것이다. 그러나 백업받은 데이터 파일은 한 달 전 파일이었고 더 큰 문제는 익스포트 백업은 테이프 이상으로 인해 복구가 불가능한 상태가 된 것이다. 백업도 없는 상황에서, 그리고 데이터베이스는 오픈되지 않는 상태에서 어떻게 한 달간의 자료를 살릴 것인가? 
그래서 필자는 항상 데이터베이스 관리자에게 당부하는 것이 백업이다. 흔히 하는 말로 “복구에 실패한 관리자는 용서할 수 있어도 백업에 실패한 관리자는 용서할 수 없다”는 말이 있다. 백업은 최대로 보수적으로 봐야 한다. 그 이유는 하드웨어라는 것들은 바로 몇 분 후에 무슨 일이 생길지 모르는 매체이기 때문이다. 테이프도 깨질 수 있고 백업 스토리지도 언제든지 망가질 수도 있다는 것을 초보 데이터베이스 관리자는 명심하기 바란다. 물론 최근의 장비들이 신뢰도가 높다고 하지만 가능성이 0%가 아니기 때문이다. 
사실 오라클에서는 데이터 파일에서 직접 데이터를 끄집어낼 수 있는 DUL(Data UnLoader)을 사용하여 깨지는 않는 데이터 파일에서 데이터를 복구할 수는 있겠지만 사실 당시에는 DUL이란 것이 있는지도 몰랐고 서비스 비용도 만만치 않은 이유도 있긴 하다.

침착한 대처는 좀 더 나은 상황을 만든다

우선 필자는 디스크 복구 여부를 확인하기 위해서 하드웨어 업체를 불렀고(물론 공유일이었으므로 서비스료를 지불했다. 당시 시간당 17만원으로 기억한다. 서비스료 산정은 다 알다시피 해당 엔지니어가 출발하는 시간부터 산출된다) 결과는 복구불능으로 파악되었다. 좀 더 복구와 관계된 조치를 하기 위해서는 미국으로 보내야 했고 기간은 한 달이 소요된다고 했다. 그러나 이 방법은 현재 상황에서는 불가능한 선택이었다. 그 이유는 바로 내일 아침에 바로 서비스가 되어야 했는데 한 달 동안 기다릴 수도 없었고 결과 또한 비관적이었기 때문이다. 그리고 깨진 디스크에 있는 데이터도 판매 데이터가 있는 디스크였기 때문에 한 달 전 자료가 있으므로, 필자는 마음을 비우고 한 달 동안의 판매 데이터를 수작업으로 입력하는 최악의 경우를 생각하고 조치방법을 생각했다. 
우선 데이터베이스를 정상적으로 오픈시켜야 했다. 오라클 관리자들은 알겠지만 No Archive Log 상태에서 데이터 파일이 깨졌을 경우에는 복구 자체가 되지 않는다. 필자는 우선 문제가 되는 데이터 파일을 offlline drop 옵션을 사용하여 오픈시켰다(<화면 1>). 또한 No Archive Log 상태로 운영 중인 데이터베이스는 offline만의 옵션으로 수행되지 않는다. 그리고 offline drop 옵션을 사용하면 해당 데이터 파일은 해당 데이터베이스에서는 영원히 사용하지 못한다.

<화면 1> OFFLINE DROP 옵션 사용 후 데이터베이스 오픈 


이때 필자의 머리에 한 가지 생각이 스치고 지나갔다(여기서부터는 약간의 데이터베이스 지식이 필요하다). 오라클 데이터베이스의 경우 하나의 테이블 스페이스에 여러 개의 데이터 파일이 존재할 수 있다. 처음에 설정한 데이터 파일이 모두 사용되면 또 다른 데이터 파일을 추가함으로써 결과적으로 하나의 테이블 스페이스에 여러 개의 데이터 파일이 존재하게 된다. 
문제의 판매용 테이블 스페이스는 4개의 데이터 파일로 구성된 것이었는데 그 중 하나가 깨진 디스크에 존재했고 이 데이터 파일을 offline drop 옵션을 사용해서 데이터베이스를 오픈시킨 것이다(<그림 1>). 필자는 그러면 안 깨진 데이터 파일에서 최근의 판매 데이터를 가지고 올 수 있는 방법이 있지 않을까 생각한 것이다.

<그림 1> OFFLINE된 데이터 파일 


그러면 해당 데이터가 어떤 데이터 파일에 있는지 알아야 하는데 이때 사용하는 것이 ROWID이다. 오라클에서는 하나의 row를 유일하게 구분하는 키 값이 ROWID이며 이 값의 포맷은 버전별로 약간 다르지만 오라클8 ROWID 포맷에 대해서는 다음의 <그림 2>에 나와 있다.

<그림 2> ROWID 포맷 


ROWID 값으로 해당 데이터가 어느 파일의 어느 블럭에 있는지 알 수 있는 것이다. 문제는 보통 테이블을 SELECT 작업을 해야 하는데 <화면 2>와 같은 에러가 나올 것이다. 이것을 보면 모든 데이터의 ROWID 값을 알기 위해서는 TABLE FULL SCAN을 해야 하는데 FULL SCAN을 하는 순간 ORA-00376 에러가 나온다는 것이다.

<화면 2> FULL SCAN시 에러 발생(ORA-00376) 


참고로 데이터가 어느 데이터 파일에 있는지 확인할 수 있는 명령문을 보면 다음과 같다. 우선 데이터 파일의 상대적인 파일 번호를 우선 알아야 되며, 해당 데이터의 ROWID에서 상대적 파일 번호를 찾아내어 비교하면 된다.

<화면 3> 상대적인 FILE 번호 


<화면 4> 상대적인 FILE 번호 


<화면 3>과 <화면 4>에서와 같이 해당 테이블 스페이스 TEST는 4개의 파일에 분포되어 있고 실제 데이터도 4개의 파일에 분포되어 있다는 것이 확인됐다(앞의 결과는 데이터 파일이 깨지기 전이므로 <화면 4>의 결과가 제대로 나온 것이다). <화면 4>에서 조건절에서 적절한 조건 값을 주면 조건 값에 맞는 데이터가 어느 데이터 파일에 있는지 나올 것이다. 
그러면 모든 데이터에 대한 ROWID도 알 수 없는 상황에서 어떻게 복구할 수 있을까? 해결책은 깨진 디스크에 있는 데이터 파일이 해당 테이블 스페이스에서 가장 먼저 만들어진 파일이라는 것에 힌트를 얻을 수 있다. 그리고 해당 테이블을 SELECT할 때는 이미 만들어져 있는 INDEX를 통해 SELECT를 해야 한다는 점, 이 두 가지를 기억해야 한다. 가장 먼저 만들어진 파일이라면 오래된 자료가 있을 가능성이 가장 높고 INDEX SCAN을 통해 최근의 데이터 중심으로 SELECT를 하면 정상적인 데이터를 얻을 수 있다. 필자의 경우에는 우선적으로 최근의 판매 데이터만을 얻으면 최상의 결론이었기 때문에 혹시 하는 생각으로 인덱스로 잡혀 있는 판매일자를 최근 한 달 것으로 SELECT를 해보았다. 결과는 대성공으로, 데이터를 가지고 올 수 있었다. 그때의 기분은 하늘을 날아갈 듯이 기뻤다. 왜냐하면 필자의 생각대로 진행이 되었기 때문이다. 이때가 개인적으로 하나의 도약을 할 수 있었던 상황으로 생각된다. 최악의 경우 수작업 입력을 생각했는데, 무작정 안 될 것이라고 포기하지 않고 데이터베이스의 기본적인 구조를 이해한 상태에서 적절한 조치를 통해 데이터를 복구할 수 있었던 것이다.

<화면 5>와 <화면 6>은 FULL SCAN과 INDEX SCAN의 차이를 극명하게 보여준다. 
<화면 5>와 <화면 6>에서와 같이 인덱스를 통한 데이터 SELECT 작업은 오류 없이 TRACE 결과를 보여주지만 해당 테이블을 FULL SCAN하는 경우에는 데이터 파일에 문제가 있기 때문에 ORA-376 에러가 난다.

<화면 5> INDEX SCAN 


<화면 6> FULL SCAN 


<그림 3> INDEX SCAN 원리 


사실 INDEX SCAN 원리(<그림 3>)는 초보 데이터베이스 관리자라도 모두 알 것이다. 그러나 중요한 요소는 그것을 적용시키는 순발력과 평상심일 것이다. 보통 당황하면 아는 것도 까먹는 경우가 많다. 특히 대안이 마땅하지 않는 경우에는 더욱 그럴 것이다. 그러나 모든 일이 대안이 없는 경우는 없다. 최악의 대안도 해법이 될 수 있기 때문이다. 그러므로 초보 데이터베이스 관리자에게 필자가 얘기하는 것은 우리가 의미 없이 지나가는 지식도 이런 상황에서는 아주 최선의 해결책이 될 수 있다는 것이다. “개똥도 약에 쓰려면 없다”는 말이 있는데 아주 흔해빠진 것이라도 정작 쓰려고 하려면 없다는 뜻이다. INDEX SCAN과 FULL SCAN은 데이터베이스에서의 아주 기본적인 개념이다. 이것을 정확히 이해하고 쓴다면 관리적인 차원에서도 많은 도움이 될 것이다. 필자도 처음부터 모든 것을 다 아는 것은 아니었고 기초적인 내용에 충실한 결과 현재가 있다고 생각한다.

기본에 충실하기 위한 생각

필자가 얘기하고 싶은 것은 항상 기본에 충실하고 아는 것도 다시 한번 보라는 것을 얘기하고 싶다. 사실 우리가 대부분의 업무에서 사용하고 있는 것은 아주 특별하고 어려운 기술을 사용하는 것이 아니고 일반적이고 쉬운 부분을 중심으로 이용한다. 이러한 일반적인 것을 해당 데이터베이스 시스템에 최선의 방안으로 선택하고 이용하는 것은 관리자의 몫이란 생각이 든다. 그리고 필자의 미숙한 글을 읽어준 사람들에게 감사를 드린다.


출처 : 마이크로소프트웨어 [2004년 11월호]

728x90

'용어' 카테고리의 다른 글

DBMS의 종류  (0) 2010.01.04
OLE DB에 대한 이야기  (0) 2009.12.17
아카이빙(Archiving) 과 백업(Backup) 의 차이점  (0) 2009.11.12
DBA란?  (0) 2009.07.08
아직도 UTF-8을 안 쓰십니까?  (0) 2009.07.08
728x90

http://cafe.naver.com/prodba/2040

728x90

'용어' 카테고리의 다른 글

DBMS의 종류  (0) 2010.01.04
OLE DB에 대한 이야기  (0) 2009.12.17
아카이빙(Archiving) 과 백업(Backup) 의 차이점  (0) 2009.11.12
당신도 데이터베이스 관리자인가요?  (0) 2009.07.08
아직도 UTF-8을 안 쓰십니까?  (0) 2009.07.08
728x90

아직도 수많은 기업에서 성능 최적화를 수행하면 서도 주어진 SQL만을 그대로 최적화하려고 하는 경우가 많다. 물론 주어진 SQL의 튜닝을 통해 성능을 최적화할 수 있는 것은 분명하다. 하지만, 우리가 생각을 전환하여 기존이 방식과 다른 방식으로 수행하여 엄청난 성능 향상을 기대할 수 있는 경우도 많다. 대용량 데이터베이스로 변하고 있는 시점에서 성능 최적화를 위해 사용자 생각의 전환은 반드시 필요한 요소다.
 
권순용 | kwontra@hanmail.net
 
 
우리 주위에는 프로젝트의 성능을 향상시키기 위해 SQL 최적화에 전념하는 사이트들이 많이 있을 것이다. SQL 최적화를 통해 크게 성능 향상을 기대할 수 있는 것은 사실이다. 예전에는 성능 저하가 발생하는 경우 SQL 튜닝 보다도 해당 시스템의 CPU 또는 디스크 등의 자원을 증설하는 부분에 초점을 맞추었었다. 이와 달리 SQL을 튜닝하여 성능을 최적화하고자 하는 것은 매우 고무적인 현상임에는 틀림 없다.
 
그 만큼 관리자들의 생각이 IT 선진화로 가는 것은 아닐까? 하지만 아직도 SQL 튜닝을 고정 관념에 맞춰 그리고 그 자체로 튜닝하고자 하는 경우가 많은 것 같다. 우리가 조금만 다르게 생각한다면 SQL 튜닝의 효과를 배가 시킬 수 있다는 것을 아는가? 주어진 SQL을 그대로 보지않고 다르게 보는 순간 우리에게는 새로운 세상이 펼쳐질 것이다.
 
데이터 삭제를 DELETE로 수행하지 않고 데이터의 갱신을 UPDATE로 수행하지 않는다면 우리에게는 새로운 세상이 펼쳐질 것이다. 이제부터 이와 같은 현상에 대해 하나하나 자세히 확인해 보자.
 
 
DML은 왜 성능을 저하시키는가?
 
 
우리가 데이터를 저장하기 위해서는 INSERT를 수행하게 되고 데이터를 제거하기 위해서는 DELETE를 수행하게 된다. 또한, 기존의 데이터를 변경하기 위해서는 UPDATE를 수행하게 된다. 이와 같은 사실은 개발을 한번이라도 한 사람이라면 아니 SQL에 관련된 책을 한번이라도 본 사람이라면 누구나 알 수 있을 것이다.
 
DML 작업을 수행한다면 그리고 DML 작업을 수행해야 하는 데이터가 매우 많다면 많은 시간이 소요될 거라고 누구나 생각할 것이다. 그렇다면 이와 같이 대용량의 데이터에 대해 DML 작업을 수행하는 경우 어떤 이유에서 많은 시간이 소요되는 것일까? 이에 대해서는 많은 사람들이 정확한 개념을 갖고 있지 못하는 것 같다. ‘나를 알고 적을 안다면 100전 100승이 되듯이’ DML 작업의 성능을 최적화하기 위해서는 DML 작업이 왜 성능을 저하시키는지를 알아야 할 것이다. DML 작업이 왜 성능을 저하시키는지 정확히 이해하지 못한다면 우리는 어떤 방법을 사용해도 성능을 향상시킬 수 없을 것이다.
 
그럼 첫 번째로 INSERT의 성능 저하를 확인해 보자. INSERT는 데이터를 저장하는 SQL 중 하나로 아래와 같은 이유에서 많은 데이터의 저장 시 성능을 저하시키게 된다.
 
·로그 기록
·HWM BUMP UP
·인덱스의 개수
·롤백을 위한 로그 기록
·디스크 I/O
 
INSERT 작업은 위와 같이 4가지 현상에 의해 성능이 저하된다. 이는 어떤 데이터베이스를 이용해도 동일하게 발생하는 현상이다. 데이터베이스는 작업의 수행도 중요하지만 작업이 실패하거나 또는 다른 장애에 의해 시스템이 재기동 되는 등의 데이터베이스 장애에 대해 데이터를 보호해야 하는 중요한 책임을 가지고 있다.
 
이와 같은 이유에서 실제 데이터베이스에서 INSERT 작업을 수행하기 전에 어떤 작업을 수행하는지에 대한 로그를 기록해야 한다. 이와 같은 기법을 선 로그(LOG AHEAD) 기법이라고 한다. 실제 INSERT를 수행하기 전에 로그를 기록하기 때문에 우리는 언제든지 INSERT 작업 중 데이터베이스에 문제가 발생해도 복구가 가능하게 되는 것이다. 실제 INSERT 작업과 관계없는 로그를 기록해야 하기 때문에 INSERT의 성능은 저하된다.
 
그렇다면 HWM BUMP UP에 의한 성능 저하는 무엇을 의미하는 것인가? HWM BUMP UP은 오라클 데이터베이스의 내부적인 요소이다. 실제 INSERT를 수행하게 되면 해당 테이블에 할당되어 있는 공간에 데이터를 저장하게 되며 해당 공간을 익스텐트라고 부르게 된다. 익스텐트에는 HWM가 설정되어 있어 데이터는 HWM 앞의 블록에만 저장된다. 이 뜻은 무엇을 의미하는 것인가?
 
HWM 앞까지 데이터를 저장한 후에는 HWM가 뒤로 후진해야만 데이터를 INSERT할 수 있다는 의미가 된다. 이를 HWM BUMP UP이라 하며 많은 데이터를 INSERT하게 되면 HWM BUMP UP은 많은 횟수가 발생하게 될 것이다. 하지만 HWM BUMP UP은 고비용의 내부적인 작업이다. 따라서 대용량의 데이터를 저장한다면 HWM BUMP UP의 횟수 증가로 INSERT의 성능은 저하된다.
 
INSERT의 속도와 인덱스의 개수는 INSERT의 성능 향상을 위해 매우 중요한 요소이다. 데이터를 테이블에 저장하는 것은 여유 공간을 가지고 있는 데이터 블록에 해당 데이터를 저장하면 된다. 하지만 인덱스에는 정해진 위치가 존재하게 되므로 정해진 위치를 찾는 프로세스가 수행된다. 따라서 해당 테이블에 인덱스가 10개라면 이와 같이 저장되는 데이터에 대해 인덱스에서의 위치를 찾기 위해 정해진 위치를 찾는 프로세스가 10번 수행되어야 할 것이다. 이와 같기 때문에 인덱스의 개수가 많다면 INSERT의 성능이 저하되는 것은 당연한 사실일 것이다.
 
어떤 사이트에서 어떤 테이블에 10개의 인덱스가 존재했으며 이를 최적화하여 5개의 인덱스로 변경한 적이 있다. 단지 10개의 인덱스를 5개로 감소시키는 순간 SQL의 변경 없이 INSERT 작업은 4배정도의 성능이 향상되었다. 이는 4배의 성능 향상이 중요한 것이 아니라 인덱스가 INSERT 작업에 많은 부하를 발생시킨다는 중요한 사실을 우리에게 전해주는 것일 것이다.
 
롤백을 위한 로그 기록은 해당 작업을 수행한 후 작업을 취소하는 경우 이전 데이터로 복구하기 위해 이전 데이터의 값을 저장하는 것을 의미한다. 이와 같은 작업 또한 실제 데이터를 저장하는 작업과는 별개로 수행되므로 INSERT의 성능 저하를 발생시키게 된다.
 
HWM BUMP UP을 제외한 로그 기록, 인덱스 및 롤백을 위한 로그 기록은 모두 디스크 I/O를 발생시킨다. 또한, 실제 데이터를 저장하는 작업에서도 디스크 I/O가 발생하게 된다. 이와 같이 모든 단계에서 디스크 I/O가 발생하기 때문에 INSERT의 성능은 저하될 것이다.
 
두 번째로 UPDATE의 성능 저하를 확인해 보자. UPDATE는 이미 저장되어 있는 데이터에 대해 변경 작업을 수행하는 것이다. 이와 같은 UPDATE는 아래와 같은 요소에 의해 성능 저하가 발생하게 된다.
 
·로그 기록
·UPDATE 컬럼이 사용된 인덱스의 개수
·롤백을 위한 로그 기록
·디스크 I/O
 
UPDATE의 경우에는 HWM BUMP UP은 발생하지 않게 된다. 또한, 인덱스의 개수도 해당 테이블에 존재하는 모든 인덱스는 아니며 UPDATE가 수행되는 컬럼이 사용된 인덱스의 개수를 의미하게 된다. UPDATE가 수행되면 해당 컬럼을 인덱스의 컬럼으로 구성하고 있는 인덱스만을 갱신하게 된다. 그렇기 때문에 UPDATE 컬럼이 사용된 인덱스의 개수에 의해 UPDATE 성능은 저하된다.
 
INSERT에 비해 UPDATE는 성능을 저하시키는 항목이 더 적다. 하지만, 동일한 양에 대해 INSERT와 UPDATE를 수행한다면 UPDATE가 성능 저하를 더 많이 발생시키게 된다. 이와 같은 이유는 왜일까? 분명히 성능 저하의 요소는 INSERT가 더 많기 때문에 INSERT가 더 많은 부하를 발생시킨다고 생각하기 쉽다. 이는 로그 기록과 롤백을 위한 로그 기록의 방식 차이 때문이다. INSERT 작업은 로그에 이전 데이터라는 것은 존재하지 않는다.
 
INSERT 작업이 수행된 데이터의 위치 정보만을 가지게 된다면 우리는 언제든지 롤백을 수행할 수 있으며 장애 시 복구도 어렵지 않게 된다. 하지만, UPDATE의 경우에는 이전 데이터의 값이 존재하기 때문에 이전 데이터를 로그에 기록하게 된다. 따라서 로그 기록 및 롤백을 위한 로그 기록에서 UPDATE가 INSERT에 비해 더 많은 데이터를 기록해야 하므로 디스크 I/O의 증가로 UPDATE의 성능은 INSERT의 성능보다 더욱 저하되게 된다.
 
세 번째로 DELETE 작업은 어떠한가? DELETE는 저장되어 있는 데이터를 삭제하는 기능을 수행하게 된다. 위와 같은 DELETE는 아래와 같은 항목들에 의해 성능이 저하된다.
 
·로그 기록
·인덱스의 개수
·롤백을 위한 로그 기록
·디스크 I/O
 
다른 항목은 INSERT 또는 UPDATE와 동일하다. 차이라면 로그 기록 및 롤백을 위한 로그 기록시 삭제되는 데이터의 이전 데이터와 이후 데이터를 모두 기록해야 한다는 것이다. 물론, 롤백을 위한 로그 기록 시에는 이전 데이터의 값과 위치 정보만을 가지게 된다. 결국, 이와 같은 이유로 동일한 양의 데이터를 DELETE하는 경우 INSERT에 비해 더 많은 디스크 I/O가 발생하게 되므로 성능은 저하되게 된다.
 
다양한 성능 저하의 요소를 가지는 DML 작업에서 대용량의 데이터에 대해서 어떤 방식으로 작업을 수행해야만 성능을 보장 받을 수 있겠는가?
 
 
INSERT의 성능 저하 요소를 감소시키자
 
 
일반적으로 DELETE 또는 UPDATE의 경우에는 INDEX의 개수만을 최적화하여 성능을 향상시킬 수 있다. 하지만, INSERT의 경우에는 위와 같은 성능 저하의 요소 중 아래와 같은 요소에 대해 획기적으로 감소시킬 수 있게 된다.
 
·로그 기록
·HWM BUMP UP
·롤백을 위한 로그 기록
 
위와 성능 저하 요소는 우리가 조금만 깊이 있게 고려한다면 최소화 시킬 수 있으며 위의 항목을 최소화 시킨다면 디스크 I/O는 자동으로 감소하게 된다. 그렇다면 어떻게 위의 성능 저하의 요소를 감소시킬 수 있겠는가?
 
첫 번째로 HWM BUMP UP과 롤백을 위한 로그 기록을 감소시키는 방법을 확인해보자. HWM BUMP UP을 제거하기 위해서는 HWM를 이동시키지 않고 데이터를 HWM 뒤에 존재하는 블록에 저장하면 될 것이다. 이와 같다면 롤백 또한 이전 데이터의 정보를 하나 하나 기록하는 것이 아니라 HWM의 위치 정보 하나만을 기록한다면 롤백 수행 시 HWM 위치 뒤에 존재하는 모든 블록을 제거한다면 롤백을 수행한 것과 동일한 현상이 발생할 것이다.
 
결국, HWM를 고정시키고 데이터를 HWM 뒤에 존재하는 블록에 저장시킨다면 HWM BUMP UP과 롤백을 위한 로그 기록에 의해 발생하는 성능 저하는 해결될 수 있을 것이다. 이와 같이 INSERT를 수행하는 방법이 바로 직접 로딩(DIRECT LOADING) 방식이다. 직접 로딩 방식을 사용한다면 HWM 뒤의 블록에 데이터를 저장하게 되므로 두 가지 문제는 모두 해결될 수 있을 것이다. 그렇다면 직접 로딩은 어떻게 사용하는 것인가?
 
·INSERT /*+ APPEND */ …… SELECT ……
 
위와 같이 SELECT를 수행하여 해당 데이터를 테이블에 INSERT하는 경우에 APPEND 힌트를 사용하여 직접 로딩을 수행하게 된다.
 
두 번째로 로그 기록을 확인해 보자. 우리가 테이블에 데이터를 저장하는 경우 일반적으로는 LOGGING 상태이므로 앞서 언급한 모든 로그를 기록하게 된다. 하지만, 직접 로딩(DIRECT LOADING) 기법을 사용하게 된다면 HWM 뒤에 존재하는 블록에 데이터를 저장하게 되므로 별도의 로그를 기록하지 않아도 복구 시 HWM 뒤의 블록에 존재하는 데이터를 제거하면 될 것이다. 이와 같은 이유에서 직접 로딩 방식의 경우에는 로그를 기록하지 않는 NOLOGGING 방식으로 데이터를 저장할 수 있게 된다.
 
결국, 위와 같이 NOLOGGING 상태에서 직접 로딩을 수행한다면 앞서 언급한 3가지의 성능 저하 요소를 대부분 제거할 수 있으며 이로 인해 디스크 I/O는 감소하게 된다. 상황에 따라 다르지만 대용량의 데이터에 대해 NOLOGGING 상태의 직접 로딩은 일반 INSERT에 비해 10배 이상 성능을 향상시킬 수도 있으며 그 이상의 성능 향상을 기대할 수도 있다.
 
 
DELETE와 UPDATE의 성능을 최적화하자
 
 
대용량의 데이터에 대해 DELETE 또는 UPDATE를 수행한다면 엄청난 성능 저하가 발생할 수 있다. DELETE 또는 UPDATE는 INSERT에 비해 더 많은 자원을 사용하게 되며 직접 로딩 또는 NOLOGGING 상태와 같은 방법이 존재하지 않게 된다. 많은 데이터에 대해서는 과거에나 지금이나 성능 저하를 감수할 수 밖에는 없을 것이다. 하지만, 이와 같은 대용량의 DELETE 또는 UPDATE에 대해서도 성능을 최적화 시키는 방법은 존재한다.
 
우리는 데이터를 변경하기 위해서는 항상 UPDATE를 사용해야 한다고 생각하고 데이터를 삭제하기 위해서는 항상 DELETE를 수행해야 한다고 생각한다. 일반적으로 생각한다면 당연한 사실일 것이다. 하지만, 이와 같은 고정 관념으로는 대용량의 데이터에서 더 이상의 성능 향상을 기대할 수 없을 것이다.
 
대용량의 데이터에 대해 UPDATE 또는 DELETE를 수행하는 경우 최적의 성능을 보장 받기 위해서는 기존의 사고 방식에서 벗어나야 할 것이다. 결국, 생각하는 방식의 전환만이 대용량의 데이터에 대해 UPDATE와 DELETE의 성능을 최적화하는 유일한 방법이 될 것이다.
 
대용량의 데이터에 대해 데이터의 변경에 대해 UPDATE로 작업을 수행하지 말고 데이터의 삭제에 대해 DELETE로 작업을 수행하지 말아야 한다. UPDATE는 INSERT로 변경하고 DELETE 또한 INSERT로 변경하는 순간 최적의 성능을 기대할 수 있을 것이다. UPDATE를 INSERT로 DELETE를 INSERT로 수행하는 것이야말로 우리의 기존 고정 관념을 파괴하는 행위일 것이다. 이제는 이와 같은 기존의 고정 관념을 파괴하여 성능을 최적화해야 할 것이다.
 
그렇다면 어떤 이유에서 UPDATE 또는 DELETE 대신 INSERT를 사용해야 하는가? 이유는 간단하다. INSERT는 UPDATE와 DELETE와는 달리 직접 로딩과 NOLOGGING이 가능하기 때문이다. 이와 같은 성능 향상의 요소는 우리에게 엄청난 혜택을 제공하기 때문이다.
 
그렇다면 어떻게 UPDATE를 INSERT로 변경하고 DELETE를 INSERT로 변경할 수 있겠는가? 물론, 데이터 삭제에 INSERT를 사용해야 하기 때문에 작업 절차는 복잡해 질 수 있다. 예를 들어, TEST 테이블의 크기가 100GB이며 그 중 50GB에 해당하는 데이터를 삭제해야 한다고 가정하자. 그렇다면 DELETE를 수행하는 순간 우리는 엄청난 시간을 기다려야 해당 작업을 종료할 수 있을 것이다.
 
DELETE를 INSERT로 변경한다면 어떻게 되겠는가? 우선, TEST 테이블과 동일 구조의 TEST_IMSI 테이블을 생성한 후 TEST 테이블로부터 데이터가 삭제된 후 남게 되는 데이터만을 조회하여 TEST_IMSI 테이블에 INSERT를 수행한다. 해당 작업에는 TEST_IMSI 테이블을 NOLOGGING 상태로 변경한 후 해당 테이블에 직접 로딩을 수행해야 할 것이다. 고성능의 디스크를 사용하는 시스템이라면 1GB에 1분 정동의 INSERT 시간이 소요된다.
 
50GB의 데이터를 INSERT하면 되므로 최적화된다면 50분 정도의 시간이 소요될 것이다. 이 얼마나 빠른 속도인가? 물론, 경우에 따라 병렬 프로세싱을 이용해야 할 수 도 있다. 이와 같이 작업을 수행했다고 모든 것이 종료되는 것은 아니다. TEST 테이블을 TEST_BACKUP으로 이름을 변경하고 TEST_IMSI 테이블을 TEST 테이블로 이름을 변경해야 할 것이다. 물론, 인덱스가 필요하다면 인덱스도 생성해야 할 것이다.
 
이와 같이 작업 절차는 복잡해 지지만 DELETE를 수행하는 것보다는 10배 아니 그 이상의 성능 향상을 기대할 수 있을 것이다. UPDATE의 경우도 이와 다르지 않다. UPDATE 후의 데이터를 임시 테이블에 INSERT를 수행하고 해당 테이블의 이름을 변경한다면 기존 테이블에는 UPDATE 후의 데이터가 저장되므로 INSERT를 이용하여 UPDATE를 대신할 수 있게 된다.
 
이와 같은 방식으로 기존의 방식에서 벗어날 수 있다면 우리는 최적의 성능을 기대할 수 있을 것이다.
 
우리가 가지고 있는 기존의 방식을 버린다는 것은 쉬운 일이 아닐 것이다. 하지만, 더 좋은 방법이 있다면 과감히 새로운 방법을 선택하는 것도 필요할 것이다. 데이터의 갱신과 제거를 UPDATE와 DELETE로 구현하는 것이 아니라 INSERT로 구현한다면 많은 사람들이 의아해 할지도 모른다. 하지만, 분명히 가능한 일이며 이를 통해 우리는 INSERT의 최고의 아키텍쳐인 NOLOGGING과 직접 로딩을 이용할 수 있다는 것을 명심하길 바란다.

제공 : DB포탈사이트 DBguide.net

728x90
728x90

ASP 등으로 되어 있는 이전 사이트들을 .NET으로 마이그레이션하다가 한번씩 겪는 문제점 중 하나는 그놈의 지긋지긋한 한글 인코딩 문제입니다.

 

그 유명한 베스트셀러(?)인 '조엘 온 소프트웨어'에서도 이러한 인코딩 문제에 대해 언급을 하고 있습니다. 미국애들 중에 몇몇이 여전히 ASCII를 쓰는 것처럼, 우리나라 개발자들 역시 여전히 KSC-5601이나 ECU-KR 인코딩을 고집하는 사람들이 많습니다.

 

심지어 일반 사용자들마저도 한글 인코딩과 관련된 문제를 겪어보지 않은 사람들이 없을 것입니다. 가장 대표적인 사례로, 페이지의 이미지가 보이지 않는 일은 누구나 겪어 봤을 것입니다. 실제 이미지가 없는 경우는 제외하고, 이 문제의 원인 중 99%는 이미지 파일 이름이 한글로 되어 있는 경우입니다.

대부분의 사이트 또는 지식검색 등에서는 IE의 옵션에서 URL을 항상 UTF-8로 보냄이라는 옵션을 꺼서 해결하라고 말하곤 합니다. 문제는 이것이 근본적인 해결책은 아니며, 한글 인코딩 문제의 해결을 더더욱 멀게 만드는 장벽이 된다는 것입니다.

 

잠깐 빗나갔는데 다시 개발에 대해서 초점을 맞춰서 다시 얘기해보겠습니다.

일반적으로 한글 인코딩과 관련된 문제가 말썽을 부릴 소지가 있는 경우는 다음과 같습니다.

1. 웹 페이지의 한글 컨텐츠가 KSC-5601이나 EUC-KR로 되어 있는 경우

2. 브라우저에서 호출하는 URL에 한글이 포함되어 있는 경우

3. 데이터베이스에서 한글 인코딩이 UTF-8이 아닌 다른 것으로 지정되어 있는 경우

 

먼저 1번의 경우..

근본적인 문제가 생기는 원인은 ASP.NET을 비롯하여 .NET에서는 기본 인코딩이 UTF-8인 것부터 출발합니다. 그러므로 예를 들어, 웹 페이지의 한글 컨텐츠가 KSC-5601이나 EUC-KR로 되어 있는 경우, 인코딩이 깨지게 되는 것입니다.

물론 이 문제의 잘못이 무조건 개발자에게만 있느냐하면, 절대 그렇지는 않습니다. 일반적으로 웹 페이지를 디자인하는 것은 웹 디자이너들의 몫이며, 이 디자이너들이 페이지를 디자인할 때 KSC-5601이나 EUC-KR을 사용해서 작성해버리는 경우가 대다수입니다.

또, 종종 개발자를 당혹스럽게 하는 것 중 하는 .inc나 .js를 통해 include한 파일의 경우입니다. 아무 이상 없이 잘 돌던 .js였는데, 단지 ASPX 내에 붙여 넣었다는 이유만으로 스크립트 에러가 발생합니다. 이러한 경우, 역시 십중팔구는 스크립트 파일 내에 한글이 포함되어 있는 경우입니다.

 

일단 이 문제를 해결할 수 있는 방법은..

각 페이지의 meta 태그 등에서 charset을 지정해주거나,

web.config에서 다음과 같이 인코딩을 지정해주는 방법이 있습니다.

 

<configuration>
   <system.web>
      <globalization 
         requestEncoding="ksc5601-1987"
         responseEncoding="ksc5601-1987"
         fileEncoding="ksc5601-1987"/>
   </system.web>
</configuration>

그런데, 이렇게 하면 정말 해결이 된 것일까요?

역시 이것 역시 임시적인 해결책에 지나지 않습니다.

더이상 인코딩 문제를 겪지 않으려면, UTF-8을 쓰는 것이 확실한 답입니다.

그러므로 바람직한 방법은 설사 디자이너가 다른 인코딩으로 전달을 해왔다고 하더라도, 메모장 등을 통해서 UTF-8로 변환해서 저장하는 것입니다. 스크립트 파일들 역시 메모장에서 연 다음 UTF-8로 변환해서 저장합니다.

 

2번의 경우.. 한글이 포함된 URL의 경우, 올바른 전송을 위해서는 한글을 URL에 맞게 인코딩을 수행해야 합니다.

 

예를 들어..

http://search.naver.com/search.naver?where=nexearch&query=한글인코딩&frm=t1

이 아니라..

http://search.naver.com/search.naver?where=nexearch&query=%C7%D1%B1%DB%C0%CE%C4%DA%B5%F9&frm=t1

가 되어야 한다는 것입니다.

(물론 네이버는 euc-kr 인코딩을 쓰고 있긴 합니다. -_-;;)

 

.NET의 경우..

문자열을 신뢰할 수 있는 URL 문자열로 만들기 위해 두 개의 메서드를 제공합니다.

HttpServerUtility.UrlEncode

HttpUtility.UrlEncode

 

이와는 반대로 다시 디코딩해서 원래의 문자로 돌리도록 다음 메서드들도 제공됩니다.

HttpServerUtility.UrlDecode

HttpUtility.UrlDecode

 

결국 Response 시에는 UrlEncode를 사용해서 인코딩을 하고, Request 받은 것을 처리할 때는 다시 UrlDecode를 사용해서 디코딩을 하는 형태로 해결을 하면 됩니다.

 

물론 이러한 부분을 처리하는데는 개발자의 귀차니즘이 수반되게 됩니다. 그 귀차니즘 덕분에 수많은 사용자들이 URL을 항상 UTF-8로 전송 옵션을 꺼야 합니다.

 

3번의 경우.. SQL 서버에서보다는 Oracle에서 많이 볼 수 있는 경우입니다.

상당수 Oracle 데이터베이스가 UTF-8이 아닌.. 심지어 US-ASCII7을 사용하는 경우가 있습니다.

대표적인 경우가 회사 내부에서 SAP을 사용하는 경우인데, 제가 알고 있기론 SAP 설치 시 기본 인코딩이 US-ASCII7인 걸로 압니다.

그래서 어떤 문제가 생기느냐? .NET에서 Oracle에 연결하기 위한 프로바이더로 ODP.NET이라는 놈이 있습니다. 이놈은 .NET이 붙은 넘 답게.. UTF-8을 사용합니다.

고로 ODP.NET을 사용하여 데이터베이스 인코딩이 US-ASCII7로 지정된 DB에서 한글 데이터를 읽으면 한글이 깨져버리는 사태가 발생하게 됩니다.

이에 대한 해결책은 DB 서버의 인코딩을 바꿔주거나, 쿼리에서 일일이 Encode 메서드를 사용해서 UTF-8로 변환하거나, 받은 후 애플리케이션 코드에서 인코딩을 변환시켜주는 수 밖에 없다는 것입니다. 어느 것 하나 쉬운게 없는데, 이러한 고생을 하는 이유가 한글 인코딩에 대해 무지했던 과거의 개발자/시스템 관리자들이 저질러 놓은 사고입니다.

 

사실 가장 이상적인 것은 Windows에서 인코딩을 UTF-8만 사용하도록 해버리면 확실한 해결책이 될지도 모릅니다. 대신 언젠가 만약 그런 날이 온다면, 기존의 UTF-8을 사용하지 않은 웹 사이트들은 문제가 생기게 되겠죠.

그러나, UTF-8이 표준화되었으므로 언젠가는 정말로 그런 날이 올지도 모릅니다. 그런 날이 오지 않기를 빌면서 통일을 반대하는 것보다는 하나씩 하나씩 바꿔 나가야 하지 않을까 합니다.

 

제발 이제는.. UTF-8을 쓰세요.


http://blog.naver.com/saltynut/120020091973

728x90

'용어' 카테고리의 다른 글

DBMS의 종류  (0) 2010.01.04
OLE DB에 대한 이야기  (0) 2009.12.17
아카이빙(Archiving) 과 백업(Backup) 의 차이점  (0) 2009.11.12
당신도 데이터베이스 관리자인가요?  (0) 2009.07.08
DBA란?  (0) 2009.07.08
728x90

The table that follows summarizes Oracle built-in datatypes. Please refer to the syntax in the preceding sections for the syntactic elements. The codes listed for the datatypes are used internally by Oracle Database. The datatype code of a column or object attribute is returned by the DUMP function.


CodeDatatypeDescription

1

VARCHAR2(size [BYTE |CHAR])

Variable-length character string having maximum length size bytes or characters. Maximum size is 4000 bytes or characters, and minimum is 1 byte or 1 character. You must specify sizefor VARCHAR2.

BYTE indicates that the column will have byte length semantics; CHAR indicates that the column will have character semantics.

1

NVARCHAR2(size)

Variable-length Unicode character string having maximum length size characters. The number of bytes can be up to two times size for AL16UTF16 encoding and three times size for UTF8encoding. Maximum size is determined by the national character set definition, with an upper limit of 4000 bytes. You must specify size for NVARCHAR2.

2

NUMBER[(precision [,scale]])

Number having precision p and scale s. The precision p can range from 1 to 38. The scale s can range from -84 to 127.

8

LONG

Character data of variable length up to 2 gigabytes, or 231 -1 bytes. Provided for backward compatibility.

12

DATE

Valid date range from January 1, 4712 BC to December 31, 9999 AD. The default format is determined explicitly by the NLS_DATE_FORMAT parameter or implicitly by the NLS_TERRITORYparameter. The size is fixed at 7 bytes. This datatype contains the datetime fields YEARMONTHDAYHOURMINUTE, and SECOND. It does not have fractional seconds or a time zone.

21

BINARY_FLOAT

32-bit floating point number. This datatype requires 5 bytes, including the length byte.

22

BINARY_DOUBLE

64-bit floating point number. This datatype requires 9 bytes, including the length byte.

180

TIMESTAMP[(fractional_seconds)]

Year, month, and day values of date, as well as hour, minute, and second values of time, where fractional_seconds_precision is the number of digits in the fractional part of the SECONDdatetime field. Accepted values of fractional_seconds_precision are 0 to 9. The default is 6. The default format is determined explicitly by the NLS_DATE_FORMAT parameter or implicitly by the NLS_TERRITORY parameter. The sizes varies from 7 to 11 bytes, depending on the precision. This datatype contains the datetime fields YEARMONTHDAYHOURMINUTE, and SECOND. It contains fractional seconds but does not have a time zone.

181

TIMESTAMP[(fractional_seconds)] WITH TIME ZONE

All values of TIMESTAMP as well as time zone displacement value, where fractional_seconds_precision is the number of digits in the fractional part of the SECOND datetime field. Accepted values are 0 to 9. The default is 6. The default format is determined explicitly by the NLS_DATE_FORMAT parameter or implicitly by the NLS_TERRITORY parameter. The size is fixed at 13 bytes. This datatype contains the datetime fields YEARMONTHDAYHOURMINUTESECONDTIMEZONE_HOUR, and TIMEZONE_MINUTE. It has fractional seconds and an explicit time zone.

231

TIMESTAMP[(fractional_seconds)] WITH LOCAL TIME ZONE

All values of TIMESTAMP WITH TIME ZONE, with the following exceptions:

  • Data is normalized to the database time zone when it is stored in the database.

  • When the data is retrieved, users see the data in the session time zone.

The default format is determined explicitly by the NLS_DATE_FORMAT parameter or implicitly by the NLS_TERRITORY parameter. The sizes varies from 7 to 11 bytes, depending on the precision.

182

INTERVAL YEAR[(year_precision)] TOMONTH

Stores a period of time in years and months, where year_precision is the number of digits in the YEAR datetime field. Accepted values are 0 to 9. The default is 2. The size is fixed at 5 bytes.

183

INTERVAL DAY[(day_precision)] TOSECOND[(fractional_seconds)]

Stores a period of time in days, hours, minutes, and seconds, where

  • day_precision is the maximum number of digits in the DAY datetime field. Accepted values are 0 to 9. The default is 2.

  • fractional_seconds_precision is the number of digits in the fractional part of the SECOND field. Accepted values are 0 to 9. The default is 6.

The size is fixed at 11 bytes.

23

RAW(size)

Raw binary data of length size bytes. Maximum size is 2000 bytes. You must specify size for a RAW value.

24

LONG RAW

Raw binary data of variable length up to 2 gigabytes.

69

ROWID

Base 64 string representing the unique address of a row in its table. This datatype is primarily for values returned by the ROWID pseudocolumn.

208

UROWID [(size)]

Base 64 string representing the logical address of a row of an index-organized table. The optional size is the size of a column of type UROWID. The maximum size and default is 4000 bytes.

96

CHAR [(size [BYTE |CHAR])]

Fixed-length character data of length size bytes. Maximum size is 2000 bytes or characters. Default and minimum size is 1 byte.

BYTE and CHAR have the same semantics as for VARCHAR2.

96

NCHAR[(size)]

Fixed-length character data of length size characters. The number of bytes can be up to two times size for AL16UTF16 encoding and three times size for UTF8 encoding. Maximum size is determined by the national character set definition, with an upper limit of 2000 bytes. Default and minimum size is 1 character.

112

CLOB

A character large object containing single-byte or multibyte characters. Both fixed-width and variable-width character sets are supported, both using the database character set. Maximum size is (4 gigabytes - 1) * (database block size).

112

NCLOB

A character large object containing Unicode characters. Both fixed-width and variable-width character sets are supported, both using the database national character set. Maximum size is (4 gigabytes - 1) * (database block size). Stores national character set data.

113

BLOB

A binary large object. Maximum size is (4 gigabytes - 1) * (database block size).

114

BFILE

Contains a locator to a large binary file stored outside the database. Enables byte stream I/O access to external LOBs residing on the database server. Maximum size is 4 gigabytes.



url : http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#i46376

728x90

+ Recent posts