데이터 블로그

AMAZON REDSHIFT. 데이터 압축2 - 압축 수행

AWS

테이블(열)에 데이터 압축을 적용하는 방법은 두 가지가 있다. 테이블에 처음으로 데이터를 로드할 때 COPY 명령을 이용해 자동으로 인코딩 형식을 지정하도록 하는 방법과 CREATE TABLE 문으로 직접 인코딩 형식을 지정하는 방법이 있다. 여기서 권장되는 방법은 COPY 명령을 이용하는 것이다.


COPY 명령

COPY 명령으로 빈 테이블에 데이터가 적재될 때 자동으로 최적의 인코딩 형식이 적용된다. 이와 관련된 옵션은 다음과 같은 것들이 있다.


  • COMPUPDATE [ON | OFF]

압축 인코딩을 자동으로 적용할지 여부를 결정한다.  COMPUPDATE 옵션을 생략했을 때는 테이블에 데이터가 없는 상태에서 테이블에 인코딩이 지정되지 않은 경우에 한해 자동으로 압축이 적용된다. COMPUPDATE 옵션을 ON으로 지정하면, 빈 테이블일 경우에 한해 이미 인코딩 유형이 지정되어 있어도 이를 무시하고 자동으로 최적의 인코딩 형식이 적용된다.


  • COMPROWS numrows

최적의 압축 인코딩을 결정하기 위해 조사할 데이터의 행 수를 지정한다. 원리는 비교적 간단하다. 여기서 지정한 행 수 만큼을 불러와 가능한 모든 인코딩 형식으로 압축해 보고, 가장 압축률이 좋은 인코딩 형식을 선택하게 된다.


행 수를 지정하지 않으면 조각(Slice) 마다 100,000개의 행이 적용된다. 행 수를 지정하면, 지정한 행 수를 총 조각수 만큼 나눈 숫자만큼 각 조각이 이용한다. 예를 들어, 클러스터에 총 4개의 조각이 있을 때, 행 수를 1,000,000으로 지정하면 각 조각마다 250,000개의 행을 이용한다.AWS Redshift 클러스터 유형별 조각수는 Amazon Redshift 클러스터 - 노드 유형에서 확인할 수 있다.


이제 실제 테이블을 만들어 COPY 명령을 이용한 예제를 살펴보자. 먼저 명시적으로 Raw 인코딩으로 테이블을 하나 생성하고, 별도로 인코딩 유형을 지정하지 않아 기본 인코딩 유형이 지정되도록 테이블을 하나 만들어 보자.



-- 명시적으로 압축하지 않도록 Raw 인코딩을 지정
create table customer
(
c_custkey		integer not null sortkey encode raw,
c_name			varchar(25) not null encode raw,
c_address		varchar(25) null encode raw,
c_city			varchar(10) null encode raw,
c_nation		varchar(15) null encode raw,
c_region		varchar(12) null encode raw,
c_phone			varchar(15) null encode raw,
c_mktsegment		varchar(10) not null encode raw
);

-- 테이블을 생성할 때 압축 인코딩을 지정하지 않아 기본 인코딩 유형이 선택된다.
create table customer_compressed
(
c_custkey		integer not null sortkey,
c_name			varchar(25) not null,
c_address		varchar(25) null,
c_city			varchar(10) null,
c_nation		varchar(15) null,
c_region		varchar(12) null,
c_phone			varchar(15) null,
c_mktsegment		varchar(10) not null
);



이제 앞에서 만든 두 테이블의 열들의 압축 인코딩을 확인하기 위해 pg_table_def  시스템 카달로그 테이블을 쿼리한다. 쿼리 결과에서 encoding 열의 값을 확인하면 압축 인코딩 유형을 알 수 있다. 결과를 보면 명시적으로 Raw 인코딩을 지정한 열들은 encoding 열 값이 none 으로 나타나 압축을 하지 않고 있음을 알 수 있다. customer_compressed 테이블의 경우 기본 인코딩 유형이 선택 되었음을 확인할 수 있다.



-- 테이블의 인코딩 유형을 확인한다.
select tablename, "column", type, encoding 
from pg_table_def 
where tablename in('customer','customer_compressed');


tablename

column

type

encoding

customer

c_custkey

integer

none

customer

c_name

character varying(25)

none

customer

c_address

character varying(25)

none

customer

c_city

character varying(10)

none

customer

c_nation

character varying(15)

none

customer

c_region

character varying(12)

none

customer

c_phone

character varying(15)

none

customer

c_mktsegment

character varying(10)

none

customer_compressed

c_custkey

integer

none

customer_compressed

c_name

character varying(25)

lzo

customer_compressed

c_address

character varying(25)

lzo

customer_compressed

c_city

character varying(10)

lzo

customer_compressed

c_nation

character varying(15)

lzo

customer_compressed

c_region

character varying(12)

lzo

customer_compressed

c_phone

character varying(15)

lzo

customer_compressed

c_mktsegment

character varying(10)

lzo



앞에서 만든 두 테이블에 COPY 명령을 이용해 데이터를 적재하여 보자. customer 테이블은 compupdate off 옵션을 이용해 자동 압축이 일어나지 않아 압축되지 않은 형태로 데이터를 저장한다. 반면에 customer_compressed 테이블은 compupdate on 옵션을 이용해 최적의 압축 인코딩을 찾도록 했다.



-- 각 테이블에 데이터를 로드한다. 아래 데이터는 AWS 계정이 있으면 누구나 접근할 수 있다.
copy customer from 's3://awssampledbuswest2/ssbgz/customer' 
credentials 'aws_access_key_id=*************;aws_secret_access_key=*************'
gzip
compupdate off  -- 압축 인코딩을 자동으로 수행하지 않는다.
region 'us-west-2';

copy customer_compressed from 's3://awssampledbuswest2/ssbgz/customer' 
credentials 'aws_access_key_id=*************;aws_secret_access_key=*************'
gzip
compupdate on  -- 압축 인코딩을 자동으로 수행한다.
region 'us-west-2';



데이터 적재가 완료되고 압축 인코딩의 변화를 살펴보기 위해 다시한번 pg_table_def  시스템 카달로그 테이블을 쿼리한다. 결과를 보면 customer_compressed 테이블의 압축 인코딩 유형이 처음과 바뀐것을 알 수 있다.



select tablename, "column", type, encoding 
from pg_table_def 
where tablename in('customer','customer_compressed');


tablename

column

type

encoding

customer

c_custkey

integer

none

customer

c_name

character varying(25)

none

customer

c_address

character varying(25)

none

customer

c_city

character varying(10)

none

customer

c_nation

character varying(15)

none

customer

c_region

character varying(12)

none

customer

c_phone

character varying(15)

none

customer

c_mktsegment

character varying(10)

none

customer_compressed

c_custkey

integer

delta

customer_compressed

c_name

character varying(25)

lzo

customer_compressed

c_address

character varying(25)

lzo

customer_compressed

c_city

character varying(10)

bytedict

customer_compressed

c_nation

character varying(15)

bytedict

customer_compressed

c_region

character varying(12)

bytedict

customer_compressed

c_phone

character varying(15)

lzo

customer_compressed

c_mktsegment

character varying(10)

bytedict



마지막으로 두 테이블과 두 테이블의 각 열들의 크기(MB)를 비교해 보자.


-- 테이블의 크기를 비교해 보자.
select "table", size
from svv_table_info
where "table" in('customer','customer_compressed');


table

size

customer

394

customer_compressed

172




-- 열 크기를 비교해 보자.
select p.name, b.col, count(*)
from stv_blocklist b
	join stv_tbl_perm p on b.tbl = p.id and b.slice = p.slice
where p.name in ('customer', 'customer_compressed')
	and b.col < 8
group by p.name, b.col
order by 1,2


name

col

count

customer                                                                

0

14

customer                                                                

1

66

customer                                                                

2

60

customer                                                                

3

46

customer                                                                

4

38

customer                                                                

5

36

customer                                                                

6

60

customer                                                                

7

40

customer_compressed                                                     

0

6

customer_compressed                                                     

1

16

customer_compressed                                                     

2

56

customer_compressed                                                     

3

6

customer_compressed                                                     

4

6

customer_compressed                                                     

5

6

customer_compressed                                                     

6

36

customer_compressed                                                     

7

6



테이블은 대략 절반 정도로 줄어 들었으며, 4번째 열(col=3)인 c_city 열은 원본이 46MB에서 6MB로 줄어 원본대비 13%로 줄어들었다.



인코딩 유형 지정

CREATE TABLE 문으로 테이블을 생성하거나 ALTER TABLE 문으로 새로운 열을 추가할 때 인코딩 유형을 지정할 수 있다. 다만 이미 데이터가 있는 테이블이려면 인코딩 유형을 변경할 수 없다. 다음은 cusomter 테이블을 만들고, 나이(age) 열을 추가할 때 인코딩 유형을 지정하는 예제이다.



create table customer 
(
c_custkey integer not null encode delta,
c_name varchar(25) not null encode zstd,
c_address varchar(25) null encode zstd,
c_city varchar(10) null encode bytedict,
c_nation varchar(15) null encode bytedict,
c_region varchar(12) null encode bytedict,
c_phone varchar(15) null encode zstd,
c_mktsegment varchar(10) not null encode bytedict
);

alter table customer
add column c_age int null encode mostly8;