바이너리 입출력

바이너리 입출력 (Binary input and output)

Snowflake는 세 가지 바이너리 포맷 또는 인코딩 방식을 지원해요: hex, base64, UTF-8이에요. 이 페이지에서는 각 포맷의 특성, 세션 파라미터가 바이너리 값의 입출력 방식을 어떻게 제어하는지, 그리고 데이터 로딩·언로딩 시 파일 포맷 옵션을 다뤄요. 마지막에는 포맷별 입출력 예제도 함께 정리했어요.

출처: Snowflake SQL Reference

본문

Snowflake는 세 가지 바이너리 포맷 또는 인코딩 방식을 지원해요: hex, base64, UTF-8.

지원되는 바이너리 포맷 개요

이 섹션은 지원되는 바이너리 포맷을 설명해요.

hex (기본값)

"hex" 포맷은 16진수(hexadecimal, base 16) 시스템을 말해요. 이 포맷에서 각 바이트는 두 문자(09의 숫자와 AF의 문자)로 표현돼요. hex로 변환을 수행할 때:

출발 대상 비고
Binary String hex는 대문자를 사용해요.
String Binary hex는 대소문자를 구분하지 않아요.

hex는 기본 바이너리 포맷이에요.

base64

"base64" 포맷은 바이너리 데이터(또는 문자열 데이터)를 인쇄 가능한 ASCII 문자(문자, 숫자, 구두점 또는 수학 연산자)로 인코딩해요. (base64 인코딩 방식은 RFC 4648에 정의되어 있어요.)

base64로 인코딩된 데이터는 다음 장점이 있어요.

  • base64로 인코딩된 데이터는 순수 ASCII 텍스트이므로, ASCII 문자 데이터는 지원하지만 BINARY 데이터는 지원하지 않는 시스템에 저장할 수 있어요. 예를 들어 음악(디지털 샘플)을 나타내는 바이너리 데이터나 만다린 언어 문자를 나타내는 UTF 데이터를 ASCII 텍스트로 인코딩해 ASCII 문자만 지원하는 시스템에 저장할 수 있어요.
  • base64로 인코딩된 데이터는 제어 문자(예: 전송 종료 문자, 탭 문자)를 포함하지 않으므로, 제어 문자가 데이터가 아니라 명령으로 해석될 위험 없이 전송·수신할 수 있어요. base64로 인코딩된 데이터는 한 번에 한 문자씩 데이터를 주고받는 구형 모뎀이나 다른 통신 장비와 호환돼요(패킷의 어느 부분이 데이터이고 어느 부분이 헤더·제어 정보인지 나타내는 패킷 헤더나 프로토콜 없이).

base64로 인코딩된 데이터는 다음 단점이 있어요.

  • 바이너리와 인쇄 가능한 ASCII 표현 사이에서 데이터를 변환하는 것은 계산 리소스를 소모해요.
  • base64로 인코딩된 데이터는 원본 데이터보다 약 1/3 더 많은 저장 공간을 필요로 해요.

다음 섹션들은 base64 인코딩에 대한 기술적 세부 사항을 제공해요.

base64 인코딩의 세부 사항

바이너리 데이터의 각 3바이트(총 24비트) 그룹은 6비트씩 4개 그룹(여전히 24비트)으로 재배열돼요. 6비트의 64가지 가능한 조합 각각은 다음 64개 인쇄 가능한 ASCII 문자 중 하나로 표현돼요.

  • 대문자 (A - Z)
  • 소문자 (a - z)
  • 10진수 (0 - 9)
  • +
  • /

또한 입력의 길이가 3의 정확한 배수가 아닐 때 패딩(padding)에 = 문자가 사용돼요.

base64로 인코딩된 데이터는 공백 문자(예: 빈칸, 줄바꿈)를 포함하지 않으므로, 원한다면 공백과 섞을 수 있어요. 예를 들어 전송자나 수신자에 줄 길이 최대 제한이 있다면, 새 줄 문자를 추가해 base64 데이터를 개별 줄로 나눌 수 있어도 데이터가 손상되지 않아요. base64로 변환을 수행할 때:

출발 대상 비고
Binary String base64는 공백이나 줄바꿈을 삽입하지 않아요.
String Binary base64는 모든 공백과 줄바꿈을 무시해요.

UTF-8

UTF-8 포맷은 유니코드용 UTF-8 문자 인코딩을 말해요.

UTF-8은 텍스트에서 바이너리로의 인코딩에 사용돼요. 모든 가능한 BINARY 값을 유효한 UTF-8 문자열로 변환할 수는 없기 때문에, UTF-8은 바이너리에서 텍스트로의 인코딩에는 사용할 수 없어요.

이 포맷은 실제로 인코딩·디코딩하기보다 기본 데이터를 한 타입 또는 다른 타입으로 재해석하는, 바이너리와 문자열 사이의 1:1 변환에 편리해요.

바이너리 값의 세션 파라미터

바이너리 값이 Snowflake로 들어오고 나가는 방식을 결정하는 두 가지 세션 파라미터가 있어요.

  • BINARY_INPUT_FORMAT: VARCHAR에서 BINARY로 변환하는 함수에 대한 VARCHAR 입력 포맷을 지정해요. 다음에 사용돼요.
    • TO_BINARY의 단일 인자 버전에서 BINARY로의 변환 수행
    • Snowflake로 데이터 로딩(파일 포맷 옵션을 지정하지 않은 경우; 아래 세부 사항 참고)

파라미터는 HEX, BASE64, UTF-8(또는 UTF8)로 설정할 수 있어요. 파라미터 값은 대소문자를 구분하지 않아요. 기본값은 HEX예요.

  • BINARY_OUTPUT_FORMAT: BINARY에서 VARCHAR로 변환하는 함수의 VARCHAR 출력 포맷을 지정해요. 다음에 사용돼요.
    • TO_CHAR , TO_VARCHAR의 단일 인자 버전에서 VARCHAR로의 변환 수행
    • Snowflake에서 데이터 언로딩(파일 포맷 옵션을 지정하지 않은 경우; 아래 세부 사항 참고)
    • 명시적으로 바이너리-투-varchar 변환을 호출하지 않았을 때 바이너리 데이터를 사람이 읽을 수 있는 포맷으로 표시(예: Snowflake 웹 인터페이스)

파라미터는 HEX 또는 BASE64로 설정할 수 있어요. 파라미터 값은 대소문자를 구분하지 않아요. 기본값은 HEX예요.

Note

바이너리에서 문자열로의 변환은 UTF-8 포맷에서 실패할 수 있으므로, BINARY_OUTPUT_FORMAT은 UTF-8로 설정할 수 없어요. 이런 상황에서 변환에 UTF-8을 사용하려면 TO_CHAR , TO_VARCHAR의 두 인자 버전을 사용해요.

파라미터는 계정, 사용자, 세션 수준에서 설정할 수 있어요. SHOW PARAMETERS 명령을 실행해 현재 세션의 모든 연산에 적용되는 현재 파라미터 설정을 확인해요.

바이너리 값 로딩·언로딩의 파일 포맷 옵션

바이너리 입출력 세션 파라미터와 별개로, Snowflake는 BINARY_FORMAT 파일 포맷 옵션을 제공해요. 이 옵션은 Snowflake 테이블로 데이터를 로딩하거나 테이블에서 언로딩할 때 바이너리 포맷을 명시적으로 제어하는 데 사용할 수 있어요.

이 옵션은 HEX, BASE64, UTF-8로 설정할 수 있어요(값은 대소문자를 구분하지 않아요). 옵션은 데이터 로딩과 언로딩 모두에 영향을 주며, 다른 파일 포맷 옵션과 마찬가지로 다음 방식으로 지정할 수 있어요.

  • 명명된 파일 포맷에서 — 이후 명명된 스테이지에서 또는 COPY 명령에서 직접 참조할 수 있어요.
  • 명명된 스테이지에서 — 이후 COPY 명령에서 직접 참조할 수 있어요.
  • COPY 명령에서 직접.

데이터 로딩

데이터 로딩에 사용될 때 BINARY_FORMAT은 스테이징된 데이터 파일에서 바이너리 값의 포맷을 지정해요. 이 옵션은 세션의 BINARY_INPUT_FORMAT 파라미터에 설정된 값을 덮어써요(바이너리 값의 세션 파라미터 참고).

옵션이 HEXBASE64로 설정된 경우, 스테이징된 데이터 파일의 문자열이 유효한 hex나 base64가 아니라면 데이터 로딩이 실패할 수 있어요. 이 경우 Snowflake는 오류를 반환한 다음 ON_ERROR 복사 옵션에 지정된 작업을 수행해요.

데이터 언로딩

데이터 언로딩에 사용될 때 BINARY_FORMAT 옵션은 지정된 스테이지의 파일로 언로딩되는 바이너리 값에 적용되는 포맷을 지정해요. 이 옵션은 세션의 BINARY_OUTPUT_FORMAT 파라미터에 설정된 값을 덮어써요(바이너리 값의 세션 파라미터 참고).

옵션이 UTF-8로 설정된 경우, 테이블의 바이너리 값 중 유효하지 않은 UTF-8이 있으면 데이터 언로딩이 실패해요. 이 경우 Snowflake는 오류를 반환해요.

예제 입출력

BINARY 입출력은 "보이는 것이 실제가 아닐 수 있어서" 헷갈릴 수 있어요.

다음 예제를 고려해요:

CREATE OR REPLACE TABLE binary_table (v VARCHAR, b BINARY);

INSERT INTO binary_table (v, b)
  SELECT 'AB', TO_BINARY('AB');

SELECT v, b FROM binary_table;

+----+----+
| V  | B  |
|----+----|
| AB | AB |
+----+----+

v(VARCHAR) 컬럼과 b 컬럼의 출력이 동일해 보여요. 그런데 b 컬럼의 값은 바이너리로 변환됐어요. b 컬럼의 값이 왜 그대로 보일까요?

정답은 TO_BINARY의 인자가 (따옴표 안에 있어 문자열처럼 보이지만) 16진수 숫자의 시퀀스로 처리된다는 거예요. 보이는 두 문자는 실제로 하나의 바이너리 데이터 바이트를 나타내는 16진수 숫자 쌍으로 해석되며, 두 바이트의 문자열 데이터가 아니에요. (입력 "문자열"에 16진수 숫자 외의 문자가 포함됐다면 동작하지 않았을 거예요. 결과는 "String '...' isn't a legal hex-encoded string"과 유사한 오류 메시지였을 거예요.)

또한 BINARY 데이터가 표시될 때 기본적으로 16진수 숫자의 시퀀스로 표시돼요. 따라서 데이터는 16진수 숫자(문자열이 아님)로 들어가고 16진수 숫자로 표시되므로, 그대로 보이는 거예요.

사실 AB라는 두 문자 문자열을 저장하는 것이 목표였다면 코드가 틀렸던 거예요. 올바른 코드는 데이터를 저장하기 전에 HEX_ENCODE 함수로 문자열을 16진수 숫자 시퀀스로 변환하고(base64 같은 다른 포맷으로 변환하는 다른 "encode" 함수를 사용해도 됨) 저장해야 해요. 예제는 아래에 있어요.

16진수("HEX") 포맷 예제

BINARY 데이터를 입력하는 한 가지 방법은 다음 예제처럼 16진수 문자 문자열로 인코딩하는 거예요.

BINARY 컬럼이 있는 테이블을 만드는 것부터 시작해요:

CREATE OR REPLACE TABLE demo_binary_hex (b BINARY);

TO_BINARY 함수로 "일반" 문자열을 유효한 BINARY 값으로 변환하려고 하면 실패해요:

INSERT INTO demo_binary_hex (b) SELECT TO_BINARY('HELP', 'HEX');

오류 메시지는 다음과 같아요.

100115 (22000): The following string is not a legal hex-encoded value: 'HELP'

이번에는 삽입하기 전에 입력을 16진수 숫자 문자열로 명시적으로 변환해요(이것은 성공할 거예요):

INSERT INTO demo_binary_hex (b) SELECT TO_BINARY(HEX_ENCODE('HELP'), 'HEX');

이제 데이터를 검색해요:

SELECT TO_VARCHAR(b), HEX_DECODE_STRING(TO_VARCHAR(b)) FROM demo_binary_hex;

+---------------+----------------------------------+
| TO_VARCHAR(B) | HEX_DECODE_STRING(TO_VARCHAR(B)) |
|---------------+----------------------------------|
| 48454C50      | HELP                             |
+---------------+----------------------------------+

보시다시피 기본적으로 출력은 16진수로 표시돼요. 원래 문자열을 되찾으려면 HEX_DECODE_STRING 함수(이전에 문자열 인코딩에 사용했던 HEX_ENCODE 함수의 보완 함수)를 사용해요.

다음 쿼리는 내부적으로 무슨 일이 일어나는지 더 자세히 보여 줘요:

SELECT 'HELP',
       HEX_ENCODE('HELP'),
       b,
       HEX_DECODE_STRING(HEX_ENCODE('HELP')),
       TO_VARCHAR(b),
       HEX_DECODE_STRING(TO_VARCHAR(b))
  FROM demo_binary_hex;

+--------+--------------------+----------+---------------------------------------+---------------+----------------------------------+
| 'HELP' | HEX_ENCODE('HELP') | B        | HEX_DECODE_STRING(HEX_ENCODE('HELP')) | TO_VARCHAR(B) | HEX_DECODE_STRING(TO_VARCHAR(B)) |
|--------+--------------------+----------+---------------------------------------+---------------+----------------------------------|
| HELP   | 48454C50           | 48454C50 | HELP                                  | 48454C50      | HELP                             |
+--------+--------------------+----------+---------------------------------------+---------------+----------------------------------+

BASE64 포맷 예제

이 섹션을 읽기 전에 16진수("HEX") 포맷 예제를 읽어 보는 것을 권장해요. 기본 개념은 비슷하고, 16진수("HEX") 포맷 예제가 더 자세히 설명해요.

BINARY 컬럼이 있는 테이블을 만드는 것부터 시작해요:

CREATE OR REPLACE TABLE demo_binary_base64 (b BINARY);

행을 삽입해요:

INSERT INTO demo_binary_base64 (b) SELECT TO_BINARY(BASE64_ENCODE('HELP'), 'BASE64');

그 행을 검색해요:

SELECT 'HELP',
       BASE64_ENCODE('HELP'),
       BASE64_DECODE_STRING(BASE64_ENCODE('HELP')),
       TO_VARCHAR(b, 'BASE64'),
       BASE64_DECODE_STRING(TO_VARCHAR(b, 'BASE64'))
 FROM demo_binary_base64;

+--------+-----------------------+---------------------------------------------+-------------------------+-----------------------------------------------+
| 'HELP' | BASE64_ENCODE('HELP') | BASE64_DECODE_STRING(BASE64_ENCODE('HELP')) | TO_VARCHAR(B, 'BASE64') | BASE64_DECODE_STRING(TO_VARCHAR(B, 'BASE64')) |
|--------+-----------------------+---------------------------------------------+-------------------------+-----------------------------------------------|
| HELP   | SEVMUA==              | HELP                                        | SEVMUA==                | HELP                                          |
+--------+-----------------------+---------------------------------------------+-------------------------+-----------------------------------------------+

UTF-8 포맷 예제

BINARY 컬럼이 있는 테이블을 만드는 것부터 시작해요:

CREATE OR REPLACE TABLE demo_binary_utf8 (b BINARY);

행을 삽입해요:

INSERT INTO demo_binary_utf8 (b) SELECT TO_BINARY('HELP', 'UTF-8');

그 행을 검색해요:

SELECT 'HELP',
       TO_VARCHAR(b, 'UTF-8')
  FROM demo_binary_utf8;

+--------+------------------------+
| 'HELP' | TO_VARCHAR(B, 'UTF-8') |
|--------+------------------------|
| HELP   | HELP                   |
+--------+------------------------+

더 알아보기 (Learn more)