본문 바로가기
SingleStoreDB/엔지니어링

SingleStore 테이블 복사 완벽 가이드: CTAS, Deep Copy, Shallow Copy 비교 분석

by 에이플랫폼 [Team SingleStore Korea] 2025. 9. 26.

 

안녕하세요! 에이플랫폼입니다. 👋

데이터를 다루다 보면 기존 테이블을 복제해야 하는 순간이 찾아옵니다.

SingleStore는 이러한 작업을 위해 여러 가지 효율적인 테이블 복사 방법을 제공합니다.

그중에서도 가장 대표적인 CTAS (CREATE TABLE AS SELECT), Deep Copy, 그리고 Shallow Copy는 각각의 특징과 장단점이 뚜렷하여 상황에 맞게 사용하는 것이 중요합니다.

이번 블로그 포스팅에서는 이 세 가지 테이블 복사 방법이 각각 무엇인지, 어떤 상황에서 사용해야 가장 효과적인지, 그리고 서로 어떤 차이점을 가지고 있는지 쉽고 명쾌하게 파헤쳐 보겠습니다. 😁

 

1. CTAS (Create Table As Select): 유연한 데이터 가공 및 복사

CTAS는 SELECT 쿼리의 결과를 그대로 새로운 테이블로 만드는, 가장 널리 쓰이고 기본적인 복사 방법입니다.

👍 장점: 최고의 유연성

SELECT 쿼리의 모든 기능을 쓸 수 있다는 것이 가장 큰 장점입니다.

특정 조건(WHERE)으로 데이터를 거르거나, 여러 테이블을 합치거나(JOIN), 심지어 Rowstore 테이블을 Columnstore로 바꾸는 등 데이터 가공과 복사를 한 번에 처리할 수 있습니다.

 

⚠️ 주의할 점: 키(Key)와 인덱스(Index)는 복사되지 않음

가장 중요한 점은, CTAS는 원본 테이블의 Sort Key, Shard Key, Index 정보를 자동으로 상속받지 않는다는 것입니다.

이 때문에 단순 CTAS 구문은 원본의 Sort Key, Shard Key, Index 설정이 없는 '기본 테이블'을 만듭니다.

물론 테이블 생성 구문에 새로운 키와 인덱스를 직접 명시해주면, 원하는 구조를 새롭게 지정하는 것은 가능합니다.

 

💡 이럴 때 사용하세요!

  • 원본의 키 구조가 필요 없는 임시 테이블을 만들 때
  • 데이터를 요약, 집계한 분석 결과를 저장할 때
  • 완전히 새로운 Key와 Index 구조를 적용하며 테이블을 복제하고 싶을 때
# 예시 원본 테이블 생성
create table original_t (
  id int primary key,
  c1 varchar(10),
  key ix_original_t (c1),
  shard key (id),
  sort key (id)
);

# 원본 테이블 값 삽입
insert into original_t select table_col as c1, c1 from table([1,2,3,4,5,6,7,8,9,10]);

# 테이블 생성 확인
show create table original_t;

# CTAS (Create Table As Select)
create table copy_t as select * from original_t;

# 테이블 생성 확인
show create table copy_t;
 

CTAS 사용시 Sort / Shard Key 및 Index 를 지정하거나 변경하고 싶은 경우 다음과 같은 구문도 가능합니다.

create table copy_t2
(sort key(id), shard key(c1), key `my_index` (c1))
as select * from original_t;

# 테이블 생성 확인
show create table copy_t2;

CTAS 사용시 Computed Column 을 추가할 수도 있습니다.

create table copy_t3
(id int, c1 int, computed_col as id+100 persisted int)
as select id, c1 from original_t;

# 테이블 생성 확인
show create table copy_t3;
 

2. CREATE TABLE LIKE : 구조만 복사

👍 장점: 완벽한 스키마 복제

CREATE TABLE LIKE의 가장 큰 장점은 데이터 없이 테이블의 구조를 원본과 100% 동일하게 복제한다는 점입니다.

CTAS와 달리 Sort Key, Shard Key, Index 등 모든 DDL 설정이 그대로 유지됩니다.

데이터는 전혀 옮기지 않으므로 실행 속도 또한 매우 빠릅니다.

 

⚠️ 주의할 점: 데이터 미포함 및 이름 중복

이름 그대로 구조만 복사하므로, 테이블은 데이터가 전혀 없는 빈 상태로 만들어집니다.

또한, Index 이름까지 원본과 동일하게 복제되므로, 같은 스키마 내에서 이름 충돌이 발생하지 않도록 주의해야 합니다.

 

💡 이럴 때 사용하세요!

  • 원본과 동일한 구조의 비어있는 테이블이 필요할 때 (예: 테스트용, 임시 데이터 저장용)
  • 테이블의 스키마(구조)만 빠르게 백업하고 싶을 때
  • 데이터까지 모두 옮기는 'Deep Copy' 작업의 첫 단계로 사용할 때
create table like_t like original_t;

# 테이블 생성 확인
select * from like_t;

show create table like_t;

3. Deep Copy

CREATE TABLE LIKE 구문 및 INSERT SELECT 을 하나의 명령어로 수행 합니다.

동일한 DDL 로 데이터까지 한번에 복제 가능 합니다.

Keyless Sharding 의 경우에도 동일한 partition 으로 복제 됩니다.

Deep Copy 방식으로 Rowstore 테이블 생성 가능합니다.

이 때 자동으로 Rowstore → Rowstore, Columnstore → Columnstore 로 복제되며 “ROWSTORE” 키워드를 명시적으로 사용할 수 없습니다.

 

👍 장점: 구조와 데이터를 한 번에 완벽 복제

Deep Copy의 가장 큰 장점은 단 하나의 명령어로 원본 테이블의 구조(DDL)와 모든 데이터를 한 번에 복제할 수 있다는 점입니다.

CREATE TABLE LIKE로 구조를 만들고 INSERT로 데이터를 채우는 두 단계 작업을 하나로 합쳐놓아 매우 편리하고 빠릅니다.

Sort/Shard Key, Index 등 모든 설정이 그대로 유지되므로 원본과 100% 동일한 '쌍둥이 테이블'을 만들 수 있습니다.

 

⚠️ 주의할 점: 테이블 타입 변환 불가

Deep Copy는 원본 테이블의 타입을 그대로 따라갑니다.

즉, Rowstore 테이블은 Rowstore로, Columnstore 테이블은 Columnstore로만 복제됩니다.

CTAS와 달리 복제 과정에서 타입을 바꾸는 것은 불가능하며, ROWSTORE 같은 키워드를 명시적으로 사용할 수도 없습니다.

 

💡 이럴 때 사용하세요!

  • 원본 테이블을 완벽하게 백업하고 싶을 때
  • 데이터까지 모두 포함된 개발 또는 스테이징 환경을 구성할 때
  • 테이블 전체를 다른 이름으로 완벽하게 복제하여 마이그레이션할 때
create table deep_t like original_t with deep copy;

# 테이블 생성 확인
show create table deep_t;

# 에러 확인
create rowstore table depp_row_t like original_t with deep copy;
>>> 
ERROR 1706 (HY000): Feature 'CREATE Explicit ROWSTORE TABLE LIKE' is not supported by SingleStore.
 

4. SHALLOW COPY

Copy On Write 방식의 테이블 복제로 실제 데이터를 물리적으로 복제하지 않으므로 거의 즉시 복제됩니다.

복제 직후 Shallow Copy 테이블과 원본 테이블의 BLOB 파일 (Column Segment) 은 공유됩니다.

원본 테이블에 변경이 일어나서 원래 BLOB 파일은 Garbage Collection 에 의해 삭제되어야 하는 경우에도 Shallow Copy 된 테이블이 참조해야만 할 경우에는 삭제되지 않습니다.

원본 테이블 및 Shallow Copy 테이블에 모두 해당 Blob 파일을 참조할 필요가 없다면 Garbage Collection 에 의해 삭제됩니다.

Shallow Copy 테이블에 변경이 발생하면 신규 BLOB 파일이 생기고, 원본 BLOB 파일과는 병합되지 않습니다. (BACKGROUND_MERGER=OFF)

원본 BLOB 파일 내부의 변경된 데이터는 Metadata 상에서 Delete Mark 처리됩니다.

 

👍 장점: 대용량 테이블도 1초 만에 복제 (제로 카피 클론)

Shallow Copy의 가장 압도적인 장점은 테이블 크기와 상관없이 거의 즉시 복제가 완료된다는 점입니다. 수십 TB짜리 테이블도 단 몇 초면 충분합니다.

이는 데이터를 물리적으로 옮기는 대신, 원본이 사용하는 데이터 파일의 주소 값만 참조하는 'Copy-On-Write' 방식으로 동작하기 때문입니다.

실제 데이터는 공유하고 있어 스토리지 공간도 거의 차지하지 않습니다.

쉽게 비유하자면 📝 원본 구글 독스(Google Docs) 문서를 '보기 권한'으로 공유하는 것과 같습니다. 문서를 복사한 게 아니라 원본을 함께 보는 것이므로 즉시 공유되고 용량도 차지하지 않죠.

⚠️ 주의할 점: 변경 시 동작 방식 이해 필요

복제 직후에는 원본과 데이터 파일을 공유하므로 완벽한 복제본처럼 보이지만, 데이터에 변경이 생기면 동작 방식이 달라집니다.

  • 수정된 데이터는 별도 파일로 생성: 원본이나 복제본 테이블에 수정이 발생하면, 변경된 내용만 별도의 새 파일에 기록됩니다. (마치 구글 독스에서 '사본 만들기'를 하는 것처럼요.)
  • 파일 참조 주의: 두 테이블 중 하나라도 원본 데이터 파일을 참조하고 있다면, 해당 파일은 삭제되지 않고 계속 유지됩니다. 이로 인해 스토리지 사용량이 예상보다 늘어날 수 있습니다.

 

⚠️ 심화 주의사항: Rowstore 및 트랜잭션 관련 동작

Shallow Copy는 Columnstore의 데이터 파일(BLOB)을 공유하는 방식이므로, 특히 Rowstore나 실시간 트랜잭션과 관련하여 다음과 같은 중요한 특징을 이해해야 합니다.

  • (복제되지 않는 데이터 🗑️) Commit은 되었지만 아직 Columnstore 파일로 저장(Flush)되지 않은 데이터는 복제 대상에서 제외됩니다. 즉, 실시간으로 유입되는 일부 최신 데이터가 복제본에 포함되지 않을 수 있습니다.
  • (빈 테이블로 복제 텅!) 순수 Rowstore 테이블을 Shallow Copy하면 공유할 Columnstore 파일이 없으므로, 내용이 전혀 없는 빈 테이블이 생성됩니다. 이 기능은 Columnstore 테이블에 최적화되어 있습니다.
  • (Lock 대기 가능성 ⏳) Shallow Copy는 실행 시점에 테이블에 EXCLUSIVE LOCK을 획득해야 합니다. 만약 다른 트랜잭션이 테이블을 사용 중이라면, 해당 작업이 끝날 때까지 Lock 대기(Wait) 상태에 빠질 수 있습니다.
  • (데이터 일관성 문제) 위 Lock 문제 때문에, 쓰기 트랜잭션이 매우 빈번한 테이블에서는 Shallow Copy가 완벽한 '특정 시점'의 복사본임을 보장하기 어려울 수 있습니다. Lock을 얻는 순간과 실제 데이터 파일의 시점이 미세하게 달라, 일부 최신 변경사항이 누락될 수 있는 것이죠.

 

💡 이럴 때 사용하세요!

  • 대용량 운영 테이블을 빠르게 복제하여 테스트 또는 개발 환경을 만들 때
  • 특정 시점의 데이터를 큰 비용 없이 스냅샷으로 생성하고 싶을 때
  • 데이터 복사에 드는 시간과 스토리지 비용을 극단적으로 절약해야 할 때
create table shallow_t like original_t with shallow copy;

# 테이블 생성 확인
show create table shallow_t;

# 복제 직후 확인
# 원본 테이블과 shallow copy 테이블은 blob 파일을 공유
select file, table_name, partition, rows_count, 
       deleted_rows_count as del_rows_cnt
from information_schema.columnar_segments 
where table_name in ('original_t', 'shallow_t') and column_name = 'id' 
order by 1, 2, 3;
# 원본 테이블 데이터 전체 변경
# 원본 테이블의 blob 파일은 교체됐지만 shallow copy 본이 참조하던 기존 blob 파일은 유지

update original_t set c1 = id + 100;
optimize table original_t flush;
# Shallow copy 테이블 일부 변경
# 해당 blob 파일의 데이터가 모두 삭제되면 최초 blob 에 대한 reference 는 사라짐
# blob 파일 중 일부 삭제된 row 는 Metadata 에 delete mark 되고 
# 해당 파일에 대한 reference 는 유지

update shallow_t set c1 = id + 100 where id <= 9;
optimize table shallow_t flush;
# Shallow copy 테이블 전체 변경
# 원본 파일에 대한 reference 는 모두 사라지고 새로 생성된 blob 파일만 유지된다.
# Background Merger 가 OFF 이므로 여러개의 blob 파일이 병합되지 않고 여러개로 유지된다.

update shallow_t set c1 = id + 100 where id = 10;
optimize table shallow_t flush;

+-------------------+------------+-----------+------------+--------------+
| file              | table_name | partition | rows_count | del_rows_cnt |
+-------------------+------------+-----------+------------+--------------+
| blobs/2/0/0/5_171 | col_t      |         1 |          4 |            0 |
| blobs/2/0/0/5_184 | shallow_t  |         1 |          3 |            0 | 
| blobs/2/0/0/5_194 | shallow_t  |         1 |          1 |            0 | # new
| blobs/3/0/0/4_175 | col_t      |         0 |          2 |            0 |
| blobs/3/0/0/4_188 | shallow_t  |         0 |          2 |            0 |
| blobs/5/0/0/6_175 | col_t      |         2 |          4 |            0 |
| blobs/5/0/0/6_188 | shallow_t  |         2 |          4 |            0 |
+-------------------+------------+-----------+------------+--------------+
7 rows in set (0.00 sec)
# Shallow copy 테이블 다시 전체 변경
# Background Merger 가 OFF 이더라도 rows 가 모두 삭제된 경우에는 GC 에 의해 
# reference 가 삭제되고 신규 생성된 Blob 파일만 관리한다.

update shallow_t set c1 = id + 1000;
optimize table shallow_t flush;

Shallow Copy 테이블에 데이터가 추가되는 경우에는 background merge 가 발생하지 않으므로 blob 파일이 삭제되지 않고 다수 생성됩니다.

Background Merger 를 ON 으로 변경하면 일반 테이블과 동일하게 사용 가능합니다.

insert into shallow_t 
  select table_col+10, table_col+10 from table([1,2,3,4,5,6,7,8,9,10]);
  
optimize table shallow_t flush;

# Background Merger ON
alter table shallow_t background_merger=on;
 

지금까지 SingleStore에서 테이블을 복사하는 네 가지 대표적인 방법을 알아보았습니다. 각 방법은 저마다의 장점과 특징이 뚜렷하여 '언제나 좋은' 방법은 없습니다. 대신 '상황에 맞는' 최선의 방법이 있을 뿐이죠. 어떤 방법을 선택해야 할지 아직 고민되신다면, 아래 표를 보고 여러분의 상황에 가장 적합한 방법을 찾아보세요!

구분
CTAS
CREATE TABLE LIKE
Deep Copy
Shallow Copy
핵심 기능
데이터 가공 + 복사
구조만 복사 (빈 테이블)
구조 + 데이터 완벽 복제
초고속 복제 (제로 카피)
데이터 복사
O (가공 가능)
X
O (전체)
O (논리적 복사)
스키마 복사
컬럼 정의만
모두 복사 (Key, Index 포함)
모두 복사 (Key, Index 포함)
모두 복사 (Key, Index 포함)
속도
데이터 크기에 비례
매우 빠름
데이터 크기에 비례
거의 즉시 (테이블 크기 무관)
이럴 때 추천!
분석용 요약 테이블 생성
구조 변경
스키마 백업
빈 테스트 테이블
완벽한 백업
개발 환경 구성
마이그레이션
대용량 테이블 스냅샷
빠른 테스트 환경 구성

각 방법의 특징을 잘 이해하고 사용한다면, 불필요한 시간과 리소스 낭비를 막는 강력한 무기가 될 것입니다.

감사합니다.