많이 쓰는 환경의 UTF-8과 EUCKR(KO16MSWIN949) 가 서버와 클라이언트가 서로 다를 때 한글이 들어오면 어떻게 되는지에 대해서 테스트 해본 자료 정리해보도록 하겠습니다.
문자셋(Character Set)과 인코딩(Encoding)
> 한글이 깨지는 문제를 해결하려면 '문자셋'과 '인코딩'이 무엇인지, 그리고 둘이 어떻게 다른지부터 이해해야 합니다.
---
1. 문자셋(Character Set)
문자셋이란 표현할 수 있는 문자들의 집합과, 각 문자에 부여된 고유 번호(코드 포인트)의 목록입니다.
쉽게 말하면 "어떤 문자가 몇 번이다" 라는 사전(dictionary) 과 같습니다.
예를 들어 유니코드(Unicode) 문자셋에서는 다음과 같이 정의합니다.
ex)
```
'A' → U+0041
'한' → U+D55C
'가' → U+AC00
'€' → U+20AC
```
여기서 `U+D55C` 같은 값이 코드 포인트(Code Point). 문자에 붙인 고유 번호일 뿐, 아직 컴퓨터에 어떻게 저장할지는 결정되지 않은 상태입니다.
대표적인 문자셋
############################################################
문자셋 설명 수록 문자
ASCII 미국 표준. 영문/숫자/특수문자 128자
KS X 1001 한국 산업표준 완성형 한글 한글 2,350자 + 한자 등
Unicode 전 세계 모든 문자를 하나의 체계로 140만자 이상
############################################################
2. 인코딩(Encoding)
인코딩이란 문자셋의 코드 포인트를 실제 컴퓨터 메모리/디스크에 저장할 수 있는 바이트(byte) 배열로 변환하는 규칙.
즉, "코드 포인트를 어떤 바이트 패턴으로 저장할 것인가"를 정의합니다.
ex)
```
문자셋 → '한' = U+D55C (코드 포인트 부여)
인코딩 → U+D55C = 0xED 0x95 0x9C (UTF-8로 저장할 때)
U+D55C = 0xC7 0xD1 (EUC-KR로 저장할 때)
```
※ 같은 문자 '한'이라도 인코딩 방식에 따라 저장되는 바이트가 완전히 달라집니다.
3. 주요 인코딩 방식
1) ASCII
1963년 미국 ANSI가 제정한 최초의 표준 문자 인코딩
7비트(128가지)로 영문 대소문자, 숫자, 특수문자 표현
한글 표현 불가
ex) 'A' → 0x41 'a' → 0x61 '0' → 0x30
2) EUC-KR
KS X 1001(한국 산업표준) 기반의 완성형 한글 인코딩
한글 1글자 = 2바이트 고정
표현 가능한 한글: 2,350자 (일부 한글 표현 불가)
옛한글, 희귀 한자 등은 지원하지 않음
ex)
'한' → 0xC7 0xD1
'글' → 0xB1 0xDB
3) MS949 (CP949)
Microsoft가 EUC-KR을 확장한 인코딩
한글 1글자 = 2바이트 고정
EUC-KR에서 표현 못하는 한글 8,822자 추가 지원
Windows 한국어 기본 인코딩
Oracle에서는 `KO16MSWIN949`로 표기
4) UTF-8
Unicode 문자셋을 바이트로 저장하는 가변 길이 인코딩
영문/ASCII: 1바이트, 한글: 3바이트, 일부 특수문자: 4바이트
전 세계 모든 문자 표현 가능
현재 웹 표준 및 대부분의 현대 시스템에서 사용
Oracle에서는 `AL32UTF8`로 표기
ex)
'A' → 0x41 (1바이트)
'한' → 0xED 0x95 0x9C (3바이트)
'😀' → 0xF0 0x9F 0x98 0x80 (4바이트)
```
5) UTF-16
모든 문자를 기본 2바이트로 저장 (일부 4바이트)
Windows 내부, Java, JavaScript 등에서 사용
BOM(Byte Order Mark)으로 빅/리틀 엔디언 구분
출처
Unicode Consortium Unicode 문자셋 표준 정의 https://www.unicode.org
RFC 3629 (IETF) UTF-8 인코딩 표준 명세 https://www.rfc-editor.org/rfc/rfc3629
RFC 20 (IETF) ASCII 표준 명세 https://www.rfc-editor.org/rfc/rfc20
KS X 1001 한국 산업표준 완성형 한글 코드 https://www.kssn.net
Microsoft Docs CP949 코드페이지 정의 https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
Oracle Docs Oracle NLS / Globalization Support Guide https://docs.oracle.com/en/database/oracle/oracle-database/19/nlspg/
W3C Character encodings for beginners https://www.w3.org/International/questions/qa-what-is-encoding
오라클에서의 캐릭터셋(Characterset in Oracle Database)
1. 캐릭터셋란 무엇인가
캐릭터셋(Character Set)이란 문자를 컴퓨터가 처리할 수 있는 숫자(바이트)로 매핑하는 규칙입니다. 같은 '한'이라는 글자도 어떤 캐릭터셋을 쓰느냐에 따라 저장되는 바이트가 달라집니다.
2. UTF-8 vs EUC-KR(MS949) 특징 비교
항목 UTF-8 EUC-KR / MS949
표준 국제 유니코드 표준 한국 산업표준 (KS X 1001)
한글 바이트 3바이트 (가변) 2바이트 (고정)
영문 바이트 1바이트 1바이트
지원 문자수 110만자 이상 (전세계 모든 언어) 한글 2,350자 (EUC-KR) / 확장 포함 MS949
Oracle 캐릭터셋 이름 AL32UTF8 KO16MSWIN949 / KO16KSC5601
옛한글·희귀한자 지원 미지원 (EUC-KR 기준)
'한' 자의 실제 바이트 값
```
UTF-8 : 0xED 0x95 0x9C (3바이트)
EUC-KR : 0xC7 0xD1 (2바이트)
Python으로 확인하는 방법:
```python
text = "한"
print(' '.join(f'0x{b:02X}' for b in text.encode('utf-8')))
# 0xED 0x95 0x9C
print(' '.join(f'0x{b:02X}' for b in text.encode('euc-kr')))
# 0xC7 0xD1
```
Oracle SQL로 확인하는 방법:
```sql
SELECT DUMP('한', 16) FROM DUAL;
-- AL32UTF8 DB: Typ=96 Len=3: ed,95,9c
-- KO16MSWIN949 DB: Typ=96 Len=2: c7,d1
```
---
3. Oracle NLS_LANG 이란
Oracle에서 클라이언트 인코딩을 선언하는 핵심 환경변수입니다.
아래 형식으로 구성되어 있습니다.
NLS_LANG = LANGUAGE_TERRITORY.CHARACTERSET
예시:
AMERICAN_AMERICA.AL32UTF8 → UTF-8
AMERICAN_AMERICA.KO16MSWIN949 → EUC-KR(MS949)
AMERICAN_AMERICA.KO16KSC5601 → EUC-KR(순수 KS)
Oracle은 NLS_LANG에 선언된 인코딩을 기준으로 데이터를 DB 캐릭터셋으로 변환합니다.
NLS_LANG이 실제 데이터 인코딩과 다르면 변환이 잘못되어 데이터가 깨집니다.
4.테스트 시나리오
클라이언트와 서버간의 캐릭터셋의 변경으로 인해 데이터가 어떻게 되는지에 대해서 확인해보겠습니다.
** 같은 '한'이라는 글자가 인코딩에 따라서 bytes수와 다르고 안에 저장된 문자형식도 다릅니다.
/****************************
EUCKR | UTF8
------------------------------
표준 한국산업표준 |유니코드 국제표준
한글 2bytes |3bytes
영문/숫자 1bytes |1bytes
지원문자 한글 2,350 |모든언어(110만자 이상)
한글범위 0xB0A1 ~ 0xC8FE |0xEAB080 ~ 0xED9EA4
미지원문자 일부한글표현 불가 |모든 문자 지원
실제 바이트 비교"한"
euckr : 0xC7 0xD1
utf8 : 0xED 0x95 0x9C
*****************************/
한글의 인코딩 확인 확인법
select dump('한',16) from dual;
SYS@dbarac1> select dump('한',16) from dual;
DUMP('한',16)
----------------------
Typ=96 Len=3: ed,95,9c
1 row selected.
서버의 캐릭터셋 확인.
저는 NLS_CHARACTERSET이 AL32UTF8인것을 확인할 수 있습니다.
SQL> select * from nls_database_parameters;
NLS_CHARACTERSET AL32UTF8
PARAMETER VALUE
-------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NLS_RDBMS_VERSION 12.2.0.1.0
NLS_NCHAR_CONV_EXCP FALSE
NLS_LENGTH_SEMANTICS BYTE
NLS_COMP BINARY
NLS_DUAL_CURRENCY $
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_SORT BINARY
NLS_DATE_LANGUAGE AMERICAN
NLS_DATE_FORMAT DD-MON-RR
NLS_CALENDAR GREGORIAN
NLS_NUMERIC_CHARACTERS .,
NLS_NCHAR_CHARACTERSET AL16UTF16
NLS_CHARACTERSET AL32UTF8
NLS_ISO_CURRENCY AMERICA
NLS_CURRENCY $
NLS_TERRITORY AMERICA
NLS_LANGUAGE AMERICAN
20 rows selected.
클라이언트의 캐릭터셋 확인.
putty에서 NLS_LANG 확인결과 AL32UTF8인것을 확인할 수 있습니다.
oracle$ echo $NLS_LANG
AMERICAN_AMERICA.AL32UTF8
테스트 테이블 생성
DB에 테스트테이블을 생성합니다.
create table charset_test (
id number,
lang_desc varchar2(100),
content varchar2(200)
);
파일로 만들어서 테스트해보기
윈도우 메모장에 각파일들에 insert문을 입력하고 저장 시에 (ANSI / UTF-8)방식으로 각각 저장하여 클라이언트의 캐릭터셋 환경을 강제로 만듭니다.

각 파일에 아래 내용 추가 후 저장(4개의 파일 생성)
euckr_han.sql (ANSI로 저장)
insert into charset_test values (1,'EUC-KR/mobaXterm','한');
commit;
euckr_han2.sql
insert into charset_test values (3,'EUC-KR/mobaXterm','한');
commit;
utf8_han.sql (UTF-8로 저장)
insert into charset_test values (2,'UTF8/mobaXterm','한');
commit;
utf8_han2.sql (UTF-8로 저장)
insert into charset_test values (4,'UTF8/mobaXterm','한');
commit;
1) case1
서버 UTF-8
클라이언트(sql파일) UTF-8
oracle$ echo $NLS_LANG
AMERICAN_AMERICA.AL32UTF8
sqlplus ysbae/"비밀번호"@DBARAC @utf8_han.sql
sql> select * from
2 charset_test;
-----------------------------
2 UTF8/mobaXterm 한
1 row selected.
Elapsed: 00:00:00.00
sql> select dump(content,16)
from charset_test
where id=2; 2 3
DUMP(CONTENT,16)
----------------------------------------------------------------------------------------------------
Typ=1 Len=3: ed,95,9c
1 row selected.
Elapsed: 00:00:00.01
3bytes (UTF8)로 잘 입력된것을 확인할 수 있습니다.
2)case2
서버 euckr
클라이언트(sql파일) euckr
한글은 깨지지만 정상적으로 UTF8형식으로 들어갑니다.
다른 툴(Oragne)로 확인결과 정상적으로 데이터가 들어간것을 확인할 수 있습니다.
즉 클라이언트쪽이 euckr이더라도 서버쪽이 UTF-8이라면 들어올 때 UTF-8로 자동변환해서 입력한다고 볼 수 있습니다.
export NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
oracle$ echo $NLS_LANG
AMERICAN_AMERICA.KO16MSWIN949
sqlplus ysbae/"비밀번호"@DBARAC @euckr_han.sql
sql> select * from charset_test where id=1;
--------------------------------
1 EUC-KR/mobaXterm ▒▒
1 row selected.
Elapsed: 00:00:00.00
sql> select dump(content,16)
from charset_test
where id=1; 2 3
DUMP(CONTENT,16)
----------------------------------------------------------------------------------------------------
Typ=1 Len=3: ed,95,9c
1 row selected.
다른 툴로 확인시
ID LANG_DESC CONTENT
--------- ------------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2 UTF8/mobaXterm 한
1 EUC-KR/mobaXterm 한
##
3)case3
서버 UTF-8
클라이언트(sql파일) euckr
한글이 깨져서 입력되는 것을 확인했고, 실제 데이터의 저장도 euckr(2bytes)로 저장된 것을 확인할 수 있습니다.
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
oracle$ echo $NLS_LANG
AMERICAN_AMERICA.AL32UTF8
sqlplus ysbae/"비밀번호"@DBARAC @euckr_han2.sql
sql> select * from charset_test where id=3;
------------------------------------
3 EUC-KR/mobaXterm ▒▒
1 row selected.
Elapsed: 00:00:00.00
sql> select dump(content,16)
from charset_test
where id=3; 2 3
DUMP(CONTENT,16)
----------------------------------------------------------------------------------------------------
Typ=1 Len=2: c7,d1
1 row selected.
###
4) case4
서버 euckr
클라이언트(sql파일) UTF-8
ora-01756에러 발생하며 데이터 입력자체가 되지 않았습니다.
export NLS_LANG= AMERICAN_AMERICA.KO16MSWIN949
oracle$ echo $NLS_LANG
AMERICAN_AMERICA.KO16MSWIN949
sqlplus ysbae/"비밀번호!"@DBARAC @utf8_han2.sql
SQL*Plus: Release 12.2.0.1.0 Production on Mon Apr 27 14:31:47 2026
Copyright (c) 1982, 2017, Oracle. All rights reserved.
Last Successful login time: Mon Apr 27 2026 14:28:23 +09:00
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
ERROR:
ORA-01756: quoted string not properly terminated
Elapsed: 00:00:00.00
Commit complete.
Elapsed: 00:00:00.00
select * from charset_test where id=4;
sql> select dump(content,16)
from charset_test
where id=4;
no rows selected
sql> select * from charset_test where id=4;
no rows selected
결론적으로 DB가 UTF-8일때 클라이언트 설정과 수행파일의 설정만 같다면(비록 둘다 euckr이더라도 ) Oracle DB에 데이터 입력시 자동변환되서 UTF-8로 들어가는 것을 확인할 수 있었습니다.
감사합니다.
'Oracle > 운영' 카테고리의 다른 글
| Linux에서 gui를 띄우기 위해서 확인해보아야 할것 (0) | 2026.04.27 |
|---|---|
| CTAS의 심화 (0) | 2026.02.02 |
| Delayed block cleanout 발생과 해결법 (0) | 2026.01.06 |
| ORA-01450: Maximum Key Length (6398) Exceeded (3) | 2025.12.19 |
| lob의 용량관리 (deduplicate 와 compress) (0) | 2025.12.17 |
댓글