2009. 12. 15. 15:45
출처 : http://www.oracle.com/technology/global/kr/index.html

Oracle Forms를 이용하여 기업용 어플리케이션을 개발할 때 요구되는 화면의 유형은 크게 두 가지로 나눌 수 있다.
하나는 입력용 화면이고 또 다른 유형은 조회용 화면이다. 입력용 화면은 데이터의 정합성 에 초점을 두어 개발이 이루어지며, 조회용 화면은 다양한 조건으로 데이터를 조회할 수 있는 기능에 초점을 맞추고 있다.

"왜 우리만 한글이 제대로 안 보이는 거야. 이거 비싼 돈 주고 도입했더니 완전 엉터리 아냐?
아니면 오라클 개발자들이 꼬부랑말 쓰는 녀석들이라는데...영 아니올시다인가?"

"그러니까 외국 제품들 쓰면 다 이 모양이라니깐.. 대한민국에 관심이나 있겠어?"

어떻게든 되게 만들어야 합니다. 어김없이 사건 현장에는 혈투를 벌이는 병사가 구원을 요청한다. "한글, 한글이 왜 깨지냐고요? 업그레이드하기 전까지는 잘 돌아갔는데 이게 무슨 경우입니까? 고객에게 어떤 답변을 해 주어야 합니까?"
제 아무리 자식을 좋은 학교에 보내어도 노심초사 자식을 걱정하는 부모의 마음처럼, 천하를 호령하고 다닌다는 오라클 데이터베이스에 데이터를 저장하고 있으면서도 고객 또한 자식같은 데이터를 잃을까 노심초사하기 마련이다.  오라클의 최전방의 병사들은 이런 고객의 마음을 헤아리고자 백방으로 문제를 해결하려고 뛰어다니면서도 머릿속에 이런 생각이 든다. "아, 왜 세상엔 다양한 언어들이 있어서..."

최전방 공격수가 아니라 다국적 소프트웨어로서의 오라클 제품의 완벽성을 위해 일하고 있는 본인의 입장에서는 처음부터 병사들의 절규들을 이해할 수 있었던 것은 아니었다. 그도 그럴 것이 많은 문제들이 소프트웨어 자체의 결함보다는 잘못된 설정과 이해에서 비롯된 것이기 때문이었다.  하지만, "소프트웨어의 글로벌화"라는 슬로건이 제대로 등장하기 시작한지는 실질적으로 아직 10년도 되지 않았다. 게다가 다국어 지원의 개념이 직접 소프트웨어의 설계에 적용되고 개발, 출시되고 사용되기까지는 그 10년 중 상당 부분이 소모되어야 했다. 그러므로 아직 시스템의 "한글화", "다국어화"라는 것이 100% 이해되기에는 무리가 있는 것이다.

"지금부터라도 제대로 "글로벌화"된 시스템을 이해하고 적용해 보는 거야!"

오라클 데이터베이스가 속편하게 입력되는 데이터를 마치 바이너리 스트림을 저장하듯이 텍스트 데이터를 언어의 특성에 맞는지 검사하거나 변환하는 작없없이 저장한다는 오히려 겉으로 드러나는 문제점이 더 적게 보이는 착시 현상이 발생할 지도 모른다.
또한 오라클 데이터베이스가 현재 사용자에 대해, 어느 나라에 있는지 고려하지 않고 단순히 날짜나 숫자 데이터를 저장만 해주고, 어떤 형식으로 날짜가 출력되어야 사용자가 이해할 수 있는지, 어떤 통화기호를 사용해야 사용자가 제대로 된 값을 이해할 수 있는지 고려하지 않는다면 오라클 데이터베이스 입장에서도 개발의 부담이 훨씬 적었을 것이다. 그 모든 것은 상위 시스템 개발자의 책임이니까......

"오라클 데이터베이스 한국어판 나왔습니까?"
오라클의 제품들은 현재 세계 140개 이상의 다양한 로케일을 지원하고 있다. 물론 한국어도 포함한다. 단순히 한국어를 포함하는 게 아니라 한국어는 "가장 중요한 10개 언어들 중 하나"의 위치를 차지하고 있다. 그런데도 "오라클 데이터베이스의 한국어판 출시 임박" 이런 광고를 본 적이 없을 것이다. 한국어 뿐 아니라 저 100개가 넘는 모든 로케일에 대해 "~~판"이라는 것은 애시당초 존재하지 않는다.
왜? 오라클 제품 자체가 "글로벌판"이기 때문이다. 출시 자체를 모든 로케일에 대한 지원이 끝난 이후에야 하게 되며, 출시된 제품에는 이미 모든 로케일에 대한 지원이 포함되어 있는 것이다. 많은 제품들이 "영어 버전"의 출시 후 수 주, 혹은 수 달 후에 "한국어판"이라는 것을 출시하는 것과는 다른 전략이다. 소프트웨어의 하부 설계 자체가 이미 다국어 지원을 고려하여 만들어졌기 때문에 가능한 것이다.

SQL> alter session set NLS_CALENDAR = 'ROC Official';

세션이 변경되었습니다.


SQL> SELECT sysdate from dual;


SYSDATE
------------------------------------------
中華民國94年07月21日
[오라클은 추가적으로 6개의 달력 시스템을 지원한다]

위에서 보듯, 여러분이 설치한 오라클 데이터베이스는 일반적으로 사용하는 Gregorian 달력 이외에 6가지 달력을 더 지원하고 있다.
이런 것이 오라클 소프트웨어만의 특징은 아닐 지라도 멋있지 않은가? "글로벌화"된 소프트웨어라는 것.

"그래서 어렵다"
이것은 오라클 제품의 강점이기도 하지만, 그래서 사람들에게 "어렵다"는 느낌을 심어준다. 왜냐하면 오라클 제품을 사용하는 사람은 결국 입맛에 맞게 설정이 끝나 있는 "한국어판"을 사용하는 것이 아니라, "글로벌판"을 입맛에 맞게 설정하여 사용해야 하기 때문이다.
하지만, 그건 단순한 이유일 뿐이다. 사실은 그 "입맛에 맞는 설정"이라는 것을 제대로 할 수 있도록 해 주는 "교본"이 없다는 것이 문제이다. 그리하여 많은 DBA들조차 초기 설정을 제대로 하지 않은 채 시스템을 도입하게 되고, 무엇이든 해 낸다(자랑스럽기도 하고 개발자로서 슬프기도 한)는 실력을 갖추고 있는 우리의 개발자들이 잘못된 설정을 가진 시스템을 기반으로 하여, 어떤 수를 써서라도 문제가 발생하지 않도록 밤을 새는 것이다. 그리 어렵지 않은 "다국어 지원"을 상식화하면, 개발자들도 억울하게 고생하지 않고 작업을 빨리 마친 후 집에 가서 재미있는 드라마도 볼 수 있는 것이다.

"알아보세. 느껴보세. 기뻐해보세"
누구나 잘 알고 있는 것 같으면서도, 누구나 잘못 사용할 수도 있는 오라클 데이터베이스의 견고한 NLS(National Language Support) 아키텍처를 어떻게 하면 문제없이 잘 사용할 수 있는지 일단 한 번 그 세계로 빠져 보기로 하자.  약 보름 간격으로 네 번에 걸쳐 오라클의 NLS 세계를 관광하고, 관광 다녀와서 이제는 개발자도 삼순이 같은 재미있는 드라마 보러 자신있게 퇴근하는 데 조금이라도 도움이 될 만한 지식 혹은 상식을 가져 보기로 하자.

PartⅠ. 오라클의 NLS 지원 특성.


1. 영역(Territory)별 지원

영국과 미국은 "영어"를 모국어로 사용하는 나라들이지만, 이들 나라에서 사용되는 날짜 표기 방법은 각각 다르다. 영국에서는 "일/월/연도"로 표기하는 반면, 미국에서는 "월/일/연도"로 표기한다. 물론 사용하는 통화기호 또한 "파운드"와 "달러"로 각각 다르다. 이렇듯, 같은 언어를 사용하는 지역이라고 해도 서로 다른 지리적, 사회적 특성으로 말미암아 서로 차이점을 가지게 마련이다.  영역 정보들이야말로, 여러분들이 NLS에 대해 "캐릭터셋 지원"이나 "번역"이상의 그 무엇으로 인식하는 데 큰 도움을 줄  것이다. 한 영역은 다음 표와 같은 고유 정보들을 포함할 수 있다.

- 달력 설정 방법 : 어떤 나라는 한 주의 첫 번 째 요일을 일요일로 생각하고(한국), 다른 나라들 중에서는 월요일(체코)로 생각할 수 있다. 또한 한 달의 첫 번 째 주를 생각할 때, 어떤 나라(체코)는 그 달의 날짜들이 해당 주의 과반수 이상을 차지하고 있을 때 그 주를 첫 번 째 주로 생각하고, 어떤 나라(한국)에서는 최초의 완전한 한 주를 그 달의 첫 번 째 달로 생각한다.


- 날짜 포맷 : 같은 날짜를 표기하는 데 각 지역마다 고유의 방식이 있음. 각 지역마다 "짧은 형식"과 "긴 날짜 형식"을 지정할 수 있다. 2005년 8월 10일이라는 날짜 데이터를, 한국에서는 "05/08/10 오후 07:28:03"로, 체코에서는 "10.08.05 19:28:03"로 제공할 수 있다.


- 통화 기호 : 각 지역마다 통화기호와 금액 표기 방식이 다르다.  또한 통화의 변경(EURO화 변경과 같이)으로 인해 두 개의 통화가 사용될 수 있고(DUAL CURRENCY), 국제적으로 통용되는 ISO 통화기호도 있다. 한국은 ₩, 체코는 Kč를 사용한다.


- 숫자 그룹 : 소수점 기호나 숫자를 그룹핑하는 방법이 지역마다 다르다. 기타 측정방식(미터방식 등)이나 반올림 방식, 음수기호의 위치 등이 지역마다 다르다. 한국에서는 소수점기호는 dot, 그룹기호는 comma이지만, 체코에서는 소수점기호가 comma, 그룹기호는 dot이다.

2. 언어(Language)적 지원

언어별로 달리 지원을 하는 특성은 다음과 같은 것이 있다.

- 캐릭터셋 : 각 언어가 저장될 수 있는 캐릭터셋을 대부분 지원한다. 한국어의 경우 KO16MSWIN949와 O16KSC5601이 있다.

- 정렬 방식 : 각 언어별로 정렬하는 규칙이 다르다. 기본적으로는 이진 바이너리 코드값을 이용해 데이터를 정렬할 수 있지만,  때에 따라서는 각 언어가 가진 글자들의 고유한 특성에 맞게 정렬을 해 줄 필요성이 있다.  이런 정렬을 Linguistic Sorting이라고 한다. 한국어에 대해서는 KOREAN_M이라는 정렬 방식을 지원한다.

- 날짜 표기에 사용되는 기호 : 날짜를 표시할 때 사용하는 month, day, day of week, year같은 정보를 그 나라에 맞게 번역하여 제공한다.

- 에러메시지 및 UI 번역 : 사용자들의 불편을 최소화하기 위해 각 언어별로 번역된 에러 메시지와 사용자 인터페이스를 제공한다.

PartⅡ. 오라클 제품 처음부터 올바르게 설치하자.

한국어 환경을 제대로 지원하려면 그림과 같이 반드시 "한국어""실행 언어"에 포함시켜야 한다. 사실 많은 DBA들이 이 부분을 간과하고 있다. 아무 생각 없이 계속 "다음(N)" 버튼만 누르다가는 돌이킬 수 없는 결과를 얻게 될 수 있으므로 이 과정은 정말 중요하다고 하겠다.



언어 선택의 의미.

"한국어"를 선택하지 않는다고 해서 한국어를 데이터베이스에 저장할 수 없다는 것은 아니다.

먼저 이 "언어 선택"에서 한국어를 선택한다는 것의 의미를 정확히 알 필요가 있다. 위에 강조한 대로 한국어를 비록 선택하지 않았다고 해서 데이터베이스에 한글 데이터를 넣을 수 없다는 것은 결코 아니다.

"한국어 저장 여부는 오로지 캐릭터셋이 무엇인가에 달렸다"

한국어를 제대로 저장하는가 여부는 오로지 다음에 언급할 캐릭터셋 설정에만 의존할 뿐, 실상"언어 선택"에서의 한국어 선택 여부는 관계없다는 점을 잘 구분해야 한다 위의 그림에서 묻는 바와 같이 이 화면은 "실행 환경"에서 어떤 언어를 지원할 것인가를 묻고 있다. 즉 여기에서 "한국어"를 선택하면 다음과 같은 리소스가 설치된다.

- 번역된 메시지 : 오라클 데이터베이스와 함께 제공되는 애플리케이션 중, iSQL*plus나 자바나 ADF 기반의 웹 애플리케이션의 경우에는 "언어 선택"과 관계없이 번역된 작업 환경이 제공된다. 하지만, SQL*Plus와 같은 기존 애플리케이션은 오라클의 번역 메시지 리소스에 의존하며 이들 파일은 각 언어별로 따로 제공된다. 만일 "한국어"를 선택하지 않으면 한국어 메시지 파일은 설치되지 않게 된다.

- 폰 트 : 오라클 ADF(UIX 혹은 CABO) 기반의 애플리케이션의 경우, "확인", "취소" 등의 버튼이 이미지로 제공되는 경우가 많다. 이런 이미지들은 번역된 메시지를 바탕으로 UIX 엔진에 의해 동적으로 생성된다. 이 이미지가 제대로 생성되기 위해서는 반드시 특정 폰트를 필요로 하게 되는데, 이 폰트는 "한국어"를 선택하지 않을 경우 설치되지 않는다. 이 특정 폰트는 한국어, 중국어(간체, 번체) 그리고 일본어에 대해 각각 제공되므로,  만일 한국어 이외에 이들 언어도 지원해야 할 경우 필수적으로 그 언어들을 선택해야 할 것이다.

- 로케일 정보 : 번역 뿐만 아니라 오라클 데이터베이스가 다양한 로케일 정보를 가진 클라이언트들과 제대로 통신하기 위해서는 각 국가별, 언어별로 특색있는 로케일 정보를 지니고 있어야 한다. 이들은 날짜 형식("2050-04-14" "Jul 9, 2005" 등), 통화 코드($) 등의 정보를 포함하고 있다. 한국어에 관한 로케일 정보를 위해 반드시 "한국어"를 선택해야 한다.

한글 Windows 혹은 LANG=ko로 설정한 유닉스 환경이 환경에서는 그림과 같이 OUI가 한글로 뜨게 된다.

기타 유닉스 환경
DBA 중에서는 "한글" 환경에서 오라클 제품을 설치하면 오동작하거나 설치되지 않는 경우가 많다고 믿는 사람들이 종종 있다. 하지만 이것은 틀린 이야기다. 오히려 한글 데이터나 한글 기반의 애플리케이션을 위해서는 한글 환경에서 오라클 제품을 설치하는 것이 실수를 줄이는 길이다.

"저희는 LANG=ko로 하면 깨진 화면이 떠서요"

하지만, 아직 리눅스 등 많은 OS에서 오라클이 제공하는 번역된 인스톨 환경을 사용할 수 없다. 오라클의 인스톨러인 OUI(Oracle Universal Installer)는 자바 기반의 애플리케이션이며, 한글출력가능 여부는 JRE(Java Runtime Engine)와 OS에 의존한다. Sun에서 제공하는 JRE의 Linux 버전은 현 시점까지는 오로지 일본어 폰트 정보(font.properties.ja)만 제공하고 있으며 한국어에 대해서는 제공하고 있지 않다. 따라서, 부득이하게 한글이 깨져서 나오게 되는 것이다. 이 경우에는 할 수 없이 LANG=C로 설정하고 영문 환경에서 오라클 제품을 설치해야 한다. 독자들은 이제 이런 상황에서 무엇을 조심해야 하는지를 깨달았을 것이다. 이 경우 "언 어 선택"에서는 오로지 "영어"만이 선택되어 있으므로, 반드시 "한국어"를 선택하고 넘어가야 할 것이다.

PartⅢ. 올바른 캐릭터 셋을 선택하자.

"올바른 캐릭터셋이라 함은 한글을 저장할 수 있는 캐릭터셋을 말한다."
자, 설치에서 한숨을 돌렸다면, 이제 실제 데이터베이스 인스턴스가 생성될 때, 올바른 캐릭터셋을 선택하는 것이 중요하다. 물론 이 사항은 오라클 많은 소프트웨어 제품들 중 데이터베이스를 설치할 때에만 해당되는 사항이다. 캐릭터셋은 잘못 설치되었을 경우에는 그야말로 치명적이다. 이런 데이터베이스에 어떤 잘못된 방식으로든 한글 바이트 코드를 저장하고 사용하게 된다면, 돌이킬 수 없는 결과를 낳게 된다.

"정해진 캐릭터셋을 가지고 있지 않은 데이터베이스에 결코 한글 데이터를 저장할 수 없다."
독자 중에는 이 말을 믿으려고 하지 않는 사람들이 있을 것이다. "설마? 내가 해 봤는데, 되던데요? 이런 생각을 가진 사람들이 있을 것이라고 믿는다. 하지만, 여러분들이 저장한 것은 결코 한글이 아니다(한글을 저장하고 사용해 왔다고 믿고 싶을 테지만). 여러분들이 저장해 온 것은 그저 한글을 가장한 이진 코드의 덩어리일 뿐이다. 데이터베이스가 여러분들이 던져주는 코드를 올바른 텍스트로 인지하는 능력을 억제시킨 채, 강제로 데이터를 저장하며 그것을 가지고 한글을 제대로 저장했다고 우길 수는 없는 것이다. 다 같이 믿자. 저 말은 부정할 수 없는 사실이며 결코 부정될 수 없다.

"왜 유독 한국 사람들은 그동안 US7ASCII 캐릭터셋을 사랑해 왔나? 이제 헤어질 때가 왔다"
현재 한글을 지원하는 캐릭터셋으로는 다음 네 가지가 있다. 오직 이 네 가지이다. 각각의 특색이 다르므로 유의해야 한다.

- KO16KSC5601
-
KO16MSWIN949
- UTF8
-
AL32UTF8

1. KO16KSC5601


이름에서 알 수 있는 바와 같이 이 캐릭터셋은 한글 완성형 코드와 일치한다. 완성형은 일반적으로 많이 사용되는 2350자의 한글을 25*94 매트릭스에 배열한 문자셋이며, 4888자의 한자와 히라카나, 카타카나, 그리고 영문 및 각종 기호들을 포함하고 있다. 유닉스 환경에서는 LANG=ko로 하여 DBCA(Database Configuration Assistant)를 실행할 경우, 자동으로 캐릭터셋을 KO16KSC5601로 지정한다. 물론 변경할 수도 있다.

"KO16KSC5601 캐릭터셋을 사용하기 전에 그 특성을 제대로 알고 사용하자"

햏햏

모두에게 하게 되었소. 솔가 예약했던 커피이 배신을 때리는 바람에 그만 낙동강 오리알이 되었지요. 정말 하오.


방각하

불행하게도 여러분의 KO16KSC5601 데이터베이스는 이 글을 제대로 저장할 수 없다. 굵게 표시된 글자는 완성형에 포함되지 않은 글자들이다. 그래서 이 글을 저장한 후 다시 읽으려고 하면 다음과 같은 결과를 보게 될 뿐이다.

? ?

모두에게 ?하게 되었소. 솔?가 예약했던 커피?이 배신을 때리는 바람에 그만 낙동강 오리알이 되었지요. 정말 ?하오.

?방각하

비록 이런 글을 올리는 게 올바른 한국어 문화에 이바지하는 길이 아니라는 것을 잘 알고 있지만, 시스템을 개발하는 사람이 사용자에게 문화 계몽을 시킬 수는 없는 노릇이다. 또한 사람의 이름을 "솔믜"라고 짓지 말라고 요구할 수도 없다. 실제로 이쁜 이름이 아닌가?

"캐릭터셋 지정 전에 반드시 사용할 시스템이 어느 정도 범위의 한글 지원을 원하는가를 확실히 검사할 필요가 있다"

2. KO16MSWIN949

Windows-949 캐릭터셋은 마이크로소프트사의 Windows Codepage 949번, 즉 한글 코드 페이지를 따른 코드셋이다.
이는 완성형(KO16KSC5601)을 그대로 포함하고 있으며, 추가로 현대 한글 조합으로 표현할 수 있는 모든 가짓수에 해당하는 8822자의 한글을 추가해 포함하고 있다. 그러니까 "Windows-949 캐릭터셋은 KSC5601의 수퍼셋(Superset)"이 되며, 따라서 "KO16MSWIN949 또한 KO16KSC5601의 수퍼셋"이 된다.

"다른 운영 체제에서도 사용할 수 있다!"
운영 체제가 Windows 949 코드 페이지를 지원하지 않는다고 해서, KO16MSWIN949 캐릭터셋을 가진 데이터베이스 인스턴스를 생성할 수 없다는 것은 아니다. 데이터베이스 캐릭터셋과 운영체제의 캐릭터셋은 전혀 별개라고 인식해야 한다. 비록 Windows-949는 특정 업체의 문자셋이기는 하지만, 이를 기반으로 한 KO16MSWIN949 캐릭터셋은 한글 2350자의 한계를 가진 KO16KSC5601의 대안으로 용이하게 이용될 수 있다. 기억하자.
Unix에서든 Linux에서든, KO16MSWIN949 캐릭터셋을 가진 데이터베이스 인스턴스를 생성할 수 있다.

3. UTF8/AL32UTF8

UTF8은 유니코드를 구현한 캐릭터셋 중에 가변길이 인코딩 방식을 택하고 있는 캐릭터셋이다. 자세한 인코딩 방식은 여기에서 논할 필요가 없지만, 가변 길이를 위해 일종의 플래그 비트를 각 바이트마다 포함시켜야 하다보니, 한 글자를 표한하는데 필요한 바이트의 길이가 최대 3바이트(AL32UTF8의 경우 6바이트)까지 늘어날 수 있다.

유니코드는 잘 알려진 바와 같이 현대 한글 11172자를 모두 가나다 순으로 잘 정렬된 상태로 포함하고 있다. 그래도 한글 한 자가 3바이트의 물리적 공간을 차지하므로, 오로지 모든 한글을 지원한다는 이유만으로 사용하는 것은 곤란하다. 하지만, 한글 이외에도 다른 언어들을 함께 데이터베이스에 저장해야 한다면 다른 선택의 여지가 없는 유일한 선택이 된다.

한글을 지원하는 캐릭터셋 비교 테이블
KO16KSC5601 KO16MSWIN949 UTF8 AL32UTF8
한글 지원상태 한글 2350자 KO16KSC5601 + 확장 8822자(총 11172자) 한글 11172자 한글 11172자
캐릭터셋/
인코딩 버전
한글완성형 완성형 코드 포함
확장된 8822자는 MS
Windows Codepage
949에 따라 배열
8.1.6 이전 :
  Unicode 2.1

8.1.7 이후:
  Unicode 3.0
9i Rel1:
  Unicode 3.0

9i Rel2 :
  Unicode 3.1

10g Rel1 :
  Unicode 3.2

1/0g Rel2 :
  Unicode 4.0
한글바이트
2바이트
2바이트
3바이트
3바이트
지원버전 7.x 8.0.6 이상 8.0 이후 9i Release 1 이상
Database Characterset으로 설정 가능 여부 가능 가능 가능 가능
National Characterset으로 설정 가능 여부 불가능 불가능 가능 불가능
한글정렬 단순 바이너리 정렬로  구현 가능


KOREAN_M 또는
UNICODE_BINARY등
특수한 옵션 필요

(한글정렬에
 관한설명참조)
한글 정렬은 단순
바이너리 정렬로 가능.
한자 정렬은
KOREAN_M 옵션 필요


장점
- 특별한 장점이 없음.
  완성형 코드만을 입출
  력하는 것이 확실할
  경우에는 높은 성능






- 2바이트로 모든 한글
  저장/입출력 가능. 공
  간의 소모가 적으면서
  도 모든 한글을 입출
  력  할 수 있다





- 현대 한글 11172자가
  정확한 순서로 배열되
  어 정렬이 효과적
- 다른 언어들(중국어
  태국어 등) 또한 같
  은 데이터베이스 인스
  턴스에 저장되어야
  할 경우 UTF8 등의 
  유니 코드 캐릭터셋
  이외에 다른 대안이
  있을 수  없음
- 한글 지원은 UTF8과
  동일








단점
- 한글을 2350자밖에
  지원하지 못한다는 치
  명적인 단점이 있어
  미래에는 사용이 자제
  되어야 할 캐릭터셋

- 완성형과 호환을 하
  려다보니, 글자배열순
  서와 정렬 순서가 다
  르게 됨. 단순한
  "ORDER BY" 절로는
  제대로 한글 정렬을
  할 수 없음
- 한글 한 캐릭터가 3바
  이트를 소모하게 되
  어 공간의 소모가 크
  고, 유니코드 인코딩/
  디코딩에 성능을 소모
  해야 한다


4. National Characterset

네셔널 캐릭터셋은 유니코드를 지원하지 않는 캐릭터셋을 가진 데이터베이스에서 유니코드를 지원하기 위해 부가적으로 설정할 수 있는 캐릭터셋이다. 즉, 하나의 데이터베이스 인스턴스는 "캐릭터셋"과 "네셔널 캐릭터셋"을 가진다. 처음 시스템 구축 당시와는 달리, 한글 이외의 다른 언어를 급히 저장해야 할 필요성이 있는 경우 네셔널 캐릭터셋을 적절히 활용할 수 있다.

네셔널 캐릭터셋을 가능한 캐릭터셋은 단 두 가지이다. UTF8과 AL16UTF16(기본값).
네셔널 캐릭터셋을 사용하기 위해서는 특정 타입으로 테이블의 컬럼 또는 PL/SQL 변수를 선언해야 한다. CHAR와 VARCHAR2,CLOB에 대응되는 네셔널 캐릭터셋 기반의 타입으로는 NCHAR, NVARCHAR2,NCLOB이 있다.

즉, KO16MSWIN949 데이터베이스에서 다음과 같이 테이블을 생성할 경우,

CREATE TABLE test_table
(  varchar_value   VARCHAR2(2000),
   nvarchar_value  NVARCHAR2(2000)
);


"varchar_value" 컬럼에는 KO16MSWIN949에 속하는 글자들만 저장할 수 있는 반면, nvarchar_value 컬럼에는 유니코드에 속한 모든 글자들을 저장할 수 있다. 약간의 부가적인 코드가 필요할 뿐, 실제 프로그래밍 방식은 거의 같다.

5. 캐릭터셋 선택의 원칙

많은 원칙이 필요없다. 다음 몇가지만 기억하자.

-
한글 지원을 위해서는 반드시 위의 네 가지 캐릭터셋 중에 하나를 선택해야 한다
-
한국에서만 사용하는 시스템이라면 KO16MSWIN949를 선택한다
-
한국어 뿐 아니라 중국어, 일본어, 러시아어 등 다양한 언어로 된 데이터를 저장해야 한다면 UTF8, AL32UTF8을 선
  택한다. 인코딩 변환으로 한국어 기반의 캐릭터셋에 비해 속도의 저하가 있다고 알려져 있다.
-
대부분이 한글이며, 일부 외국어가 필요하다면, 한국어 기반의 캐릭터셋(KO16MSWIN949)을 사용하되, National
  Characterset을 이용한 컬럼에 외국어를 저장한다.

PartⅣ. 올바른 NLS 환경변수값 설정하기.

"모로 가도 서울만 가면 된다"고 자동차에 대한 지식없이 어떻게 하다보니까 차를 뒤로 움직이게 되어, 후진으로만 목적지에 도달한다면 과연 목적지에 잘 도달했다고 칭찬받아야 할까? 그 답은 "예"일 수도, "아니오"일 수도 있지만, "모로 가도 한글만 나오면 된다"는 식으로 구축된 시스템에 대해서는 무조건 "아니오"가 답이다. 많은 시스템들이 제대로 운전에 대한 지식과 준비 없이 시스템을 목적지로 운전시키고 있다.

오라클 데이터베이스는 무려 20개의 다양한 NLS 환경변수를 제공한다. 하지만 염려는 붙들어 매길...... 그렇다고 해서 20개 모두의 씀씀이를 다 알아야 한국어데이터를 제대로 다룰 수 있다는 의미는 아니다. "손가락만 까딱해도 된다"는 요즘 자동차들이 제공하는 수많은 기능들 중에 핵심적인 기능만 알아도 안전운전을 할 수 있듯이, 몇 가지 핵심적인 변수의 의미만 제대로 파악하고 제대로 사용한다면 그야말로 "안전한" 한국어 환경을 구축할 수 있는 것이다.

1. NLS_LANG

1) NLS_LANG 변수의 구성
NLS_LANG 변수는 단순히 하나의 변수가 아니라 실질적으로 NLS 연산의 모든 것을 결정한다고 해도 틀리지 않은 세 가지 정보를 포함하고 있는 중요한 변수이다.

NLS_LANG = [언어]_[영역].[캐릭터셋]

정 의 가능한 값
언어
현재 사용자가 사용하는 언어적 특성을 결정짓는 값 SQL> select parameter,value from V$NLS_VALID_VALUES where parameter like '%LANG%' ORDER BY value;
...
KOREAN
LATIN AMERICAN SPANISH
...
TRADITIONAL CHINESE
..
VIETNAMESE
영역
현재 사용자가 위치한 영역의 특성을 결정짓는 값 SQL> select parameter,value from V$NLS_VALID_VALUES where parameter like '%TERR%' ORDER BY value;
...
KOREA
...
SAUDI ARABIA
...
YUGOSLAVIA
캐릭 터셋
현재 사용자의 시스템이 인식할 수 있는 캐릭터셋의 값 SQL> select parameter,value from V$NLS_VALID_VALUES where parameter like '%CHARACTERSET%' ORDER BY value;
..
KO16KSC5601
..
KO16MSWIN949
..
WE8DEC
..
ZHT16MSWIN950
KOREAN_KOREA.KO16KSC5601
KOREAN_KOREA.KO16MSWIN949
AMERICAN_AMERICA.US7ASCII
AMERICAN_AMERICA.WE8ISO8859P1
JAPANESE_JAPAN.JA16SJIS
.KO16MSWIN949
.UTF8

2) NLS_LANG 변수값 설정의 기본 원칙
"제 데이터베이스가 UTF8인데, NLS_LANG도 .UTF8로 해야 하는 거 아닌가요?"
땡, 틀렸다. NLS_LANG 변수가 데이터베이스 캐릭터셋과 값이 항상 같아야 한다면 무엇하러 설정하겠는가?

"NLS_LANG 변수는 데이터베이스에게 사용자의 환경을 알려주는 인식표 역할을 한다"
그렇다. NLS_LANG 변수의 값은 멀리 있는 데이터베이스의 환경이 아니라, 사용자 자신이 속해 있는 환경을 도리어 데이터베이스에 알려주는 역할을 하는 변수이다.

NLS_LANG을 다음과 같이 설정해 보자.

> set NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949

이는 사용자 자신이 미국의 영어를 쓰고, 아메리카 영역 내에 있으며, 가진 컴퓨터가 사용하는 캐릭터셋은 KO16MSWIN949라는 의미이다.

> sqlplus scott/tiger
SQL> select x from y;
select x from y
*
ERROR at line 1:
ORA-00942: table or view does not exist


SQL> select hiredate from emp;

HIREDATE
------------
17-DEC-80
...

18 rows selected.

이와 같이 모든 메시지나 날짜 형식을 미국에 맞게 표현해 준다.

SQL> exit

이제 NLS_LANG을 다음과 같이 변경해 보자.

> set NLS_LANG=KOREAN_KOREA.KO16MSWIN949

이는 사용자 자신이 한국어를 쓰고, 한국 영역 내에 있으며, 가진 컴퓨터가 사용하는 캐릭터셋은 KO16MSWIN949라는 의미이다.

SQL> select hiredate from emp;

HIREDATE
--------

80/12/17
..

18 개의 행이 선택되었습니다.


이제 한국의 날짜 형식과 함께 한국어로 메시지를 보여주게 된다.


이에따라, Windows 운영체제에서 한국어환경을 사용하는 사용자들은 다음과 같이 NLS_LANG 값을 설정할 수 있다. KOREAN_KOREA.KO16MSWIN949

그리고, 유닉스 운영체제에서 한국어를 입출력한다면 다음과 같이 NLS_LANG을 설정할 수 있다.
KOREAN_KOREA.KO16KO16KSC5601

데이터베이스가 UTF8이든 KO16MSWIN949이든 상관없이 한글을 지원하는 데이터베이스와 통신한다면 반드시 위와 같이 NLS_LANG값을 설정해야 한다.


3) 데이터베이스의 캐릭터셋과 동일한 값으로 캐릭터셋을 설정하는 경우
데이터베이스의 데이터는 사용자로 전달될 때, NLS_LANG에 설정된 캐릭터셋에 기반해 적절히 변환되어 전달된다.
즉 내부적으로는 한글이 UTF8로 저장되어 있다 할 지라도, NLS_LANG의 값에 따라 UTF8로 인코딩된 문자열을 Windows 949 코드 페이지로 변환하여 사용자에게 전달하게 되는 것이다.

NLS_LANG 값에 있는 캐릭터셋을 UTF8로 설정하는 경우가 꼭 없는 것은 아니다. 만일 데이터베이스의 캐릭터셋이 UTF8인 상태에서, 질의를 요청한 사용자의 NLS_LANG의 값도 .UTF8이라면, 데이터베이스에서는 단순히 UTF8 문자열을 사용자에게 전달하게 되며 이를 어떻게 사용할 지는 사용자의 몫에 달려 있다.

NLS_LANG 값을 데이터베이스 캐릭터셋에 맞추는 경우는 대략 다음과 같은 경우가 있다.

- 데이터베이스로부터 데이터를 export받을 때
- export 받은 데이터베이스와 같은 캐릭터셋을 가진 데이터베이스로 export된 파일을 import할 때 기타 다국어 지원
  애플리케이션에서 목적에 따라 사용할 수 있다.

[주요 NLS 변수 요약]

변수명 정의 기본값 설정 설정방법
NLS_TERRITORY 영역 설정 NLS_LANG 변수값에 의해 자동 설정 초기화변수
ALTER SESSION
SET NLS_TERRITORY =
'KOREA'
NLS_LANGUAGE 언어 설정 NLS_LANG 변수값에 의해 자동 설정 초기화변수
ALTER SESSION
SET NLS_TERRITORY =
'KOREAN'
NLS_LANG 언어,영역,
캐릭터셋
설정
AMERICAN_AMERICA.US7ASCII OS 환경변수
NLS_COMP SQL에서의
비교 방식
(<,>,=)
설정
BINARY값으로 비교 초기화변수,OS환경변수
ALTER SESSION
SET NLS_COMP = ''
NLS_SORT
문자열의 정렬방법 설정
NLS_LANGUAGE값에 따라 결정
초기화변수,OS환경변수
ALTER SESSION SET NLS_SORT = 'KOREAN_M'
NLS_TERRITORY 변수에 따라 그 값이 결정되는 변수:

- NLS_CREDIT
  (대차대조표 '대변'항목의 금액표기를 위한 기호. 보통 '공백'문자)

- NLS_CURRENCY
- NLS_DATE_FORMAT
- NLS_DEBIT
  (
대차대조표 '차변'항목의 금액표기를 위한 기호. 보통 '마이너스'문자)

- NLS_ISO_CURRENCY
- NLS_LIST_SEPARATOR
  (숫자를 가로로 나열할 때 각 숫자를 구분하는 기호로, 우리나라의 경우 콤마이다)

- NLS_MOMETARY_CHARACTERS
  (금액 표기시 금액을 읽기 쉽게 나누는 문자로 우리나라에서는 3자리마다 ","를 추가한다)

- NLS_NUMERIC_CHARACTERS
  (소수점기호와 숫자 그룹핑을 위한 문자 설정. 우리나라에서는 '.,'이다 (dot와 comma)

- NLS_TIMESTAMP_FORMAT
- NLS_TIMESTAMP_TZ_FORMAT
- NLS_DUAL_CURRENCY
  (유로화 변경 기간동안의 혼란을 막기 위해 만들어진 매개변수. 9i Release 2과 그 이후로는 EU의 유로화 변경이 완
   료된 상태로 NLS_CURRENCY와 값이 동일하다. 다만 미래에 다른 지역에서도 통화기호의 변경이 일어나면 사용
   될 수 있다)


NLS_LANGUAGE 변수에 따라 그 값이 결정되는 변수:

- NLS_DATE_LANGUAGE
-
NLS_SORT


*초기화변수 : init.ora또는 spinit.ora에 설정되어 데이터베이스 구동시에 자동 설정될 수 있는 변수를 의미함

*OS환경변수 : OS에서 초기화 방식(setenv, export 등)으로 값을 할당,변경할 수 있는 변수

PartⅤ. KO16KSC5601에 서 지원되지 않는 글자들을 KO16KSC5601 데이터베이스에 입출력하기.

이제는 KO16KSC5601 캐릭터셋은 “ㅤㅅㅛㅍ”, “ㅤㅃㅙㄼ”과 같은 글자를 지원하지 않는다는 것을 알게 되었을 것이다.
그저 한글 하면 “KSC5601”을 떠 올리는 것이 보통이니 이런 사실을 아는 것만으로 획기적인 사고의 전환이 가능하다
.

“우리 시스템은 일반 사용자의 다양한 의견을 게시판을 통해 수렴하고 있다. 어떤 한글이 입력될 지 모르는 상황이다. KO16KSC5601”은 한글을 2350자밖에 지원하지 않으므로 사용하지 않아야겠다."

이런 매끄러운 사고가 가능한 것이다. 그러면 어떻게 KO16KSC5601에서 지원되지 않는 글자들을 KO16KSC5601” 데이터베이스에 입출력할 수 있는가? 결론은 이렇다.

“그런 일은 있어서도 안 되고, 가능하지도 않다”
실망스러운가? 하지만 엄연한 사실이며, 여러분들은 이 말을 아주 심각하게 받아들여야 한다. 하지만 여전히 여러분들보다 생각이 덜 하는 사람들, 심각하게 받아들이지 않는 사람들이 있다.

“KO16KSC5601”에 얼마든지 그런 글자들을 삽입할 수 있던데요?
그래서 그런 사람들에게 직접 예를 보여줄 수 있다. 한글 윈도우 상에서 다음과 같은 질의를 보여주자.
한글 Windows 운영체제이므로 암시적으로 NLS_LANG의 값은 KOREAN_KOREA.KO16MSWIN949라고 생각하면 된다.

DOS> sqlplus scott/tiger@KSC5601DB

SQL> create table charset_test(charcol VARCHAR2(100), ncharcol NVARCHAR2(100));

SQL> insert into charset_test(charcol) values(' ㅅㅛㅍ');

1 개의 행이 만들어졌습니다.

SQL> select charcol from charset_test;

CHARCOL
-------------------------------------------------------


“ ㅅㅛㅍ”이라는 글자는 INSERT 문장 실행시 에러가 발생되지는 않았지만 결국 제대로 된 값이 삽입되지 않았다. 여기서 다시 “삽입할 수 있다”파는 다음과 같은 주장을 펼칠 수 있다.

“NLS_LANG =.KO16KSC5601로 설정하면 결국 캐릭터셋과 NLS_LANG 값이 일치하여 제대로 삽입할 수 있을 것이다.”

그래서 이렇게 시도를 할 수 있다. 어떤 결과가 나오는지 살펴보자.

DOS> set NLS_LANG=.KO16KSC5601

DOS> sqlplus scott/tiger@KSC5601DB

SQL> insert into charset_test(charcol) values('ㅤㅅㅛㅍ');

ERROR:

ORA-01756: quoted string not properly terminated


이번에는 오히려 INSERT 문장 자체가 실패한다. 어떻게 이런 결과가 나올까? 앞서 NLS_LANG에 대해 배운 바로는 분명히 NLS_LANG 변수와 데이터베이스의 캐릭터셋이 일치할 경우 데이터의 변환 없이 데이터가 그대로 삽입되게 된다. 그런데 삽입 문장 자체가 실패하다니? 하지만 놀랄 필요없다. 그저 이것은 당연한 결과이다. 개발자 여러분은 최대한 단순해질 필요가 있다. 개발자들은 가끔 너무 잘 하려고 하는 경향이 있으며, 안 되는 것은 없다고 생각한다. 하지만 모든 꼼수는 결국 가까운 미래에 자기 자신에게 부메랑이 되어 격무의 부담으로 돌아온다는 사실을 꼭 기억하자.

“지원되지 않는 글자를 데이터베이스에 삽입하지 말자”

인정하건대 글자에 따라, 프로그래밍 방식에 따라 지원되지 않는 글자들로 연산이 가능한 때가 있다.
단순히 NLS_LANG과 데이터베이스 캐릭터셋이 일치하는 바람에 들어가지 못할 데이터가 들어가게 되는 경우가 있다. 예를 들어 위의 “ㅤ숖”자 대신에 역시 완성형에서 지원되지 않는 글자인 “똠”을 테스트하면 엉뚱하게 들어가게 된다. 그렇지만 이것은 단순히 “우연의 일치”일 뿐이다. 1바이트와 2바이트가 섞여 있는 캐릭터셋에서 한 글자의 끝을 인식하는 과정에서 우연히도 “ㅤ똠”이 그 과정을 무사히 통과했을 뿐이다. 그렇지 않으면 대부분 “ㅤ숖”과 같이 엉뚱하게 “문 자열이 제대로 끝나지 않았다”는 에러를 만나게 된다. 확인할 겸 몇 글자 더 시도해 보기로 하자.

DOS> set NLS_LANG=.KO16KSC5601

DOS> sqlplus scott/tiger@KSC5601DB

SQL> insert into charset_test(charcol) values('숖');

ERROR:

ORA-01756: quoted string not properly terminated

SQL> insert into charset_test(charcol) values('똠');

1 row created.

SQL> insert into charset_test(charcol) values('믜');

ERROR:

ORA-01756: quoted string not properly terminated

SQL> insert into charset_test(charcol) values('뾃');

1 row created.

SQL> insert into charset_test(charcol) values('햏');

1 row created.

SQL> select charcol from charset_test;

CHARCOL
---------------------------------------


햏/p>


일부 OCI나 MS 기반의 애플리케이션에서 NLS_LANG과 캐릭터셋이 일치하는 바람에 지원되지 않는 글자들을 삽입하고 조회할 수 있기도 한다. 지금 얼마나 많은 오라클 데이터베이스 인스턴스에서 이런 현상이 벌어지고 있는지 상상하기조차 힘들다. 하지만 미래에는 그런 일이 일어나지 않아야겠다. 왜냐하면 그런 잘못된 구성으로 인해 발생하는 힘든 일은 모두 개발자가 감당하고 있기 때문이다.

PartⅥ. 오라클 데이터베이스에서의 한글 정렬.

1. KO16KSC5601 데이터베이스

KO16KSC5601에서는 한글 2350자의 바이너리 정렬 순서가 한글의 언어적 정렬 방식과 동일하다. 따라서, 단순한 ORDER BY 명령어만으로 정렬의 효과를 거둘 수 있다. 그리고, 한자의 경우 한글 뒤에 한자의 음에 맞게 정렬이 된다. 예에 나와 있는 한자들은 "가구","류","애"로 모두 잘 정렬되어 있는 것을 볼 수 있다. 하지만 명심하라, 단지 한글 2350자들과 한자 4888자의 정렬일 뿐이다. 나머지 글자들에 대해서는 입출력도 불가능하거니와, 입출력을 무슨 수를 써서 했다고 하더라도 정렬이 제대로 될 리가 없다.

SQL> SELECT text FROM nlstech_sample_sort_ksc5601 ORDER BY text;

TEXT
------------------------------------------------------------
가나다라마바사
라디오를켜라
可口

// 한글, 한자의 정렬이 올바르다

실제로 잘 만들어진 프레임워크의 내부를 보면 좋다고 알려진 패턴을 구현한 것인 경우가 많고 구조는 잘 정의된 패턴에 기반하고 있는 경우가 일반적이다. 프레임워크는 디자인 패턴들을 실제로 구현한 결과이고 프레임워크를 문서화할 때는 패턴을 통해서 기술하는 것이 효과적이다.

2. UTF8/AL32UTF8 데이터베이스 UTF8 데이터베이스의 경우, 한글만을 고려하면 별다른 정렬 옵션이 필요없다. 왜냐하면 한글 11172자의 정렬 순서와 바이트 코드 정렬 순서가 일치하기 때문이다. 한글만의 정렬에 관해서는 정확성과 성능을 모두 만족한다고 볼 수 있다.

데이터베이스에서 예제 실행:

SQL> SELECT * FROM nlstech_sample_sort_ko ORDER BY text;

TEXT
------------------------------------------------------------
가나다라마바사
똠각하
라디오를켜라
먄해
햏햏 

// 정렬 결과가 올바르다


하지만, 한자까지 고려한다면 이것도 역시 완벽한 방법은 아니다. 다음 예제를 보자.

SQL> SELECT text FROM nlstech_sample_sort_unicode_b ORDER BY text;

TEXT
-----------------------------------------------------------
可口


가나다라마바사
똠방각하
라디오를켜라
먄해
햏햏


한자의 경우도 단순히 유니코드 내의 바이트 코드값에 의존하게 되면 별다른 의미를 찾을 수 없는 배열만을 얻게 된다. 이 경우에는 특정 NLS_SORT 매개변수 값을 지정함으로써 좀 더 의미있는 결과를 얻을 수 있다.


NLS_SORT=’KOREAN_M’ 이용

NLS_SORT 값을 설정할 수 있는 방법에 대해서는 이미 앞에서 설명한 바가 있다.

9i부터 지원되는 ‘KOREAN_M’ 정렬 방식을 이용하면 한자에 관련되어 몇 가지 원칙이 적용된다.

- 한글은 단순히 유니코드 바이트 정렬에 의존한다
- 모든 한글은 한자에 우선한다
-
한자는 발음 순서대로 정렬된다

한 마디로 KO16KSC5601에서 사용되던 정렬 방식으로 모든 한글과 한자를 정렬하겠다는 방법이다.

3. KO16MSWIN949 데이터베이스


KO16MSWIN949는 KO16KSC5601에서 지원되지 않는 8822자의 한글을 추가적으로 지원한다는 점에서 KO16KSC5601의 대안으로 자주 이용되는 캐릭터셋이다. 하지만, 기존 KO16KSC5601의 수퍼셋으로 군림하려다 보니 총 11172자의 한글의 바이트 코드가 한글의 언어적 정렬 순서와 불일치할 수 밖에 없다.

KO16MSWIN949 데이터베이스에서 실행:

SQL> SELECT * FROM nlstech_sample_sort_unicode_b ORDER BY text;

TEXT
------------------------------
똠방각하
먄해
가나다라마바사
라디오를켜라
햏햏

// 정렬 결과가 엉뚱하다


이를 극복하기 위해서는 단순한 바이트코드 정렬방식이 아니라 다른 정렬방식을 적용해야 한다.

방법 1) NLS_SORT=’UNICODE_BINARY’ 이용

현재 사용자 세션의 기본 정렬 방식을 변경하여 해결:

SQL> ALTER SESSION set NLS_SORT = 'UNICODE_BINARY'; 

세션이 변경되었습니다.

SQL> SELECT * FROM nlstech_sample_sort_unicode_b ORDER BY text;

TEXT
------------------------------
가나다라마바사
똠방각하
라디오를켜라
먄해
햏햏



질의 자체에 NLS_SORT 값을 지정해 주는 방법:

SQL> SELECT text FROM nlstech_sample_sort_ko
ORDER BY NLSSORT(text,'NLS_SORT=UNICODE_BINARY');

TEXT
------------------------------
가나다라마바사
똠각하
라디오를켜라
먄해
햏햏



방법 2) NLS_SORT=’KOREAN_M’ 이용

한자 데이터까지 고려하면 ‘KOREAN_M’을 사용하는 것이 좋다.

UNICODE_BINARY 사용:

SQL> SELECT text FROM nlstech_sample_sort_korean_m
ORDER BY NLSSORT(text,'NLS_SORT=UNICODE_BINARY');

TEXT
------------------------------
可口


가나다라마바사
똠방각하
라디오를켜라
먄해
햏햏 

// 한자의 정렬 또한 단순히 유니코드 바이트 코드에 의존한다.



KOREAN_M 사용:

SQL> SELECT text FROM nlstech_sample_sort_korean_m ORDER BY NLSSORT(text,'NLS_SORT=KOREAN_M');

TEXT
------------------------------
가나다라마바사
똠방각하
라디오를켜라
먄해
햏햏
可口



// 한자가 발음 순서대로 정렬되어 있다(가 애)

4. 인덱스를 이용하여 성능 향상시키기. 미리 NLSSORT를 이용한 인덱스를 생성하면 비록 디스크 공간이 더 필요하기는 하지만, 편리하고 성능도 좋아진다.
인덱스는 각 NLS_SORT 값별로 여러 개를 생성할 수 있다. 어느 인덱스를 사용할 것인지는 NLS_SORT 변수의 값에 달려 있다.

KO16MSWIN949 데이터베이스에서 실행:

SQL> CREATE INDEX nlstech_sample_sort_ub ON nlstech_sample_sort_ms949 (NLSSORT(text, 'NLS_SORT = UNICODE_BINARY'));

인덱스가 생성되었습니다.

SQL> CREATE INDEX nlstech_sample_sort_km ON nlstech_sample_sort_ms949 (NLSSORT(text, 'NLS_SORT = KOREAN_M'));

인덱스가 생성되었습니다.

SQL> ALTER SESSION set NLS_SORT = 'UNICODE_BINARY';

세션이 변경되었습니다.

// UNICODE_BINARY 인덱스가 사용된다

SQL> SELECT text FROM nlstech_sample_sort_ms949 ORDER BY text;

TEXT
------------------------------
可口


가나다라마바사
똠방각하
라디오를켜라
먄해
햏햏

8 개의 행이 선택되었습니다.

SQL>
SQL> ALTER SESSION set NLS_SORT = 'KOREAN_M';

세션이 변경되었습니다.

// KOREAN_M 인덱스가 사용된다

SQL> SELECT text FROM nlstech_sample_sort_ms949 ORDER BY text;

TEXT
------------------------------
가나다라마바사
똠방각하
라디오를켜라
먄해
햏햏
可口

8 개의 행이 선택되었습니다.



NLS_SORT의 값으로 설정할 수 있는 것은 버전 별로 다를 수 있다. 이는 각 버전마다 존재하는 Globalization Support Guide(8.1.7 이전에는 Nationa Language Support Guide)를 참조하면 부록에서 발견할 수 있다. 하지만 본인이 운영하는 데이터베이스라면 대략 다음과 같은 질의로 확인할 수 있다.

SQL> select value from V$NLS_VALID_VALUES where parameter = 'SORT' ORDER BY value
..
BINARY
...
KOREAN_M
...
UNICODE_BINARY
..

PartⅦ. 오라클 데이터베이스에서 한글 비교하기.

앞선 팁에서 짐작할 수 있듯이, 정렬이 원하는 대로 되지 않는다면, 비교 또한 제대로 될 리가 없다. 두꺼운 책의 마지막에 있는 인덱스(찾아보기)나 사전처럼, 한글 키워드를 ‘가나다’ 그룹으로 만들기 위해서는 정렬과 비교가 필수적인 기능이다.

"오라클의 기본 비교 방식은 BINARY"

정렬도 그렇지만, 비교할 경우에도 역시 오라클 데이터베이스는 기본적으로 BINARY 방식을 사용한다. 같은 글자라 해도 이진 코드는 각 캐릭터셋마다 다르므로 어떤 캐릭터셋에서는 “>”의 결과가 나왔던 비교문도 다른 캐릭터셋에서는 “<”의 결과가 나올 수도 있다. 우리는 이미 어떤 정렬 방식을 지정하면 제대로 정렬이 되는지 앞선 팁에서 익혔으므로, 이제 여기서는 오라클이 비교를 수행할 경우에도 내부적으로 같은 방식을 사용할 것을 지시하기만 하면 된다.

1.NLS_COMP.

NLS_COMP 변수는 오라클이 비교 연산들을 수행할 시 어떤 방식을 사용할 지를 지정하는 변수이다. 복잡한 NLS_SORT와는 달리 이 변수의 값으로는 오로지 BINARY 또는 ANSI 두 값만이 허용된다. BINARY는 기본으로 설정되어 있는 값으로 비교 연산은 이진 바이트 코드의 비교로 이루어진다는 것을 의미한다. 하지만, ANSI라고 설정하면, 같은 비교 연산자의 수행 방식이 이진 비교에서 언어적 비교(Linguistic Comparison)으로 전환된다. 즉, 우리가 NLS_SORT 변수에 설정한 정렬 방식이 비교 연산자(>, <, BETWEEN 등)들에게 약발이 먹힌다는 의미이다.

NLS_SORT와는 달리 이 값은 NLSSORT 함수의 내부 패러미터가 아니므로, SQL 질의문 내에 사용될 수는 없다.
데이터베이스 초기화 패러미터(init.ora)로 지정되거나 환경 변수, 세션 변수로 지정되어야 한다.

ALTER SESSION SET NLS_COMP=ANSI;
또는
ALTER SESSION SET NLS_COMP=BINARY;


그렇다면 다음을 살펴보자.

KO16MSWIN949 데이터베이스에서:

SQL> SELECT text FROM nlstech_sample_comp_ms949;

TEXT
------------------------------
루비
다대기
두상이크다
병원
도망
나름대로
도도하다
똠방각하
거위
도시남녀
너도밤나무

TEXT
------------------------------
구씨가족
라면

13 개의 행이 선택되었습니다.


정렬되지 않은 이 문자열들의 집합에서 ‘ㄷ’ 에 속한 문자열들만을 추출하기를 원한다고 치자.
그렇다면 먼저 다음과 같이 시도해 볼 수 있다.

SQL> SELECT text FROM nlstech_sample_comp_ms949 WHERE text >= '다' AND text < '라';

TEXT
------------------------------
다대기
두상이크다
도망
도도하다
도시남녀


제대로 된 것 같지만, 똠방각하가 누락되었다. 그 이유는 짐작할 수 있을 것이다.
KO16KSC5601에 포함되어 있지 않은 이라는 글자는 아쉽게도 이진 정렬에서는 제대로 된 결과를 보여주지 못한다.

그래서 이번에는 다음과 같이 시도해 보기로 한다.

SQL> ALTER SESSION SET NLS_SORT='KOREAN_M';

세션이 변경되었습니다.

SQL> SELECT text FROM nlstech_sample_comp_ms949 WHERE text >= '다' AND text < '라';

TEXT
------------------------------
다대기
두상이크다
도망
도도하다
도시남녀


애석하게도 결과는 똑같다. 분명히 NLS_SORT 값을 ‘KOREAN_M’으로 설정하여 정렬 시 유니코드 이진 값을 기준으로 정렬할 것을 명시했지만, 비교 연산자의 수행 시, 이 원칙이 지켜지지 않았다. 그래서 이번에는 비교 연산을 수행할 때, NLS_SORT에서 명시한 언어별 정렬 방식을 사용할 것을 명령해 보자.

SQL> ALTER SESSION SET NLS_SORT='KOREAN_M';

세션이 변경되었습니다.

SQL> ALTER SESSION SET NLS_COMP=ANSI;

세션이 변경되었습니다.

SQL> SELECT text FROM nlstech_sample_comp_ms949 WHERE text >= '다' AND text < '라';

TEXT
-----------------------------
다대기
두상이크다
도망
도도하다
똠방각하
도시남녀

6 개의 행이 선택되었습니다.

이제야 비로소 제대로 된 결과가 나오는 것을 알 수 있다.
Posted by 옹니미