요약
주가 분석 프로젝트를 InnoDB에서 Iceberg로 옮기며 두 엔진의 내부 구조를 비교했습니다.
개발자 마크 폴은 주가 분석 프로젝트 StockAlgo를 MySQL InnoDB로 한 번, Iceberg 레이크하우스(객체 저장소 위에서 표 형식 데이터를 관리하는 구조)로 한 번 만들었습니다. 분석 쿼리는 테이블마다 두세 개 열만 읽는데 InnoDB는 행 전체를 읽는다는 점을 뒤늦게 깨달은 것이 계기였습니다.
왜 중요한가
- 같은 일을 두 엔진으로 직접 만들어 보며, 작업 성격에 따라 맞는 엔진이 다르다는 점을 구체적으로 보여 줍니다.
- 쓸 때 통계를 남기고 읽을 때 걸러내는 방식은 Snowflake, BigQuery, Delta Lake도 같아서 한 번 익히면 두루 통한다고 했습니다.
핵심 내용
- 지표 하나에 필요한 열은 36개 중 2개뿐이어도 InnoDB는 행 전체를 메모리로 읽어 들였습니다.
- Iceberg는 매니페스트 목록, 매니페스트, Parquet 행 그룹의 최솟값·최댓값 통계로 읽을 필요 없는 파일을 미리 건너뜁니다.
- 커밋은 새 메타데이터 파일을 쓴 뒤 카탈로그 Polaris의 포인터를 중간 상태 없이 한 번에 바꾸는 동작이 전부입니다.
- 쓰기 충돌은 잠금 대신 커밋 때 바뀐 파일이 겹치는지 확인하고 재시도하는 방식으로 처리합니다.
- 파티션 정보가 메타데이터에 있어서, InnoDB에서 며칠에서 일주일 걸리던 파티션 재구성이 메타데이터 수정으로 끝납니다.
HN 반응
- InnoDB 기본 행 형식은 페이지 절반을 넘는 큰 값을 따로 떼어 저장하므로, 모든 열을 늘 함께 둔다는 설명은 틀렸다는 지적이 나왔습니다.
- 다음 실험으로 DuckDB를 권하는 댓글이 이어졌고, 한 이용자는 Python과 Postgres로 6시간 넘게 걸리던 분석이 30분 남짓으로 줄었다고 전했습니다.
행은 모든 컬럼을 함께 저장한다
보장되는 게 아닙니다. DYNAMIC(기본값)과 COMPRESSED 행 형식[0]에서는 가변 길이 컬럼의 큰 값이 페이지 밖(off-page) 레코드로 밀려날 수 있습니다. 글의 예시에서는 그런 일이 생기지 않겠지만, 어디까지나 보장은 아닙니다. 이는 Postgres의 TOAST와 대략 비슷합니다. 다만 Postgres는 TOAST 기본 임계값이 페이지의 1/4(기본 페이지 크기 8KiB에서 2KiB)인 반면, InnoDB는 페이지의 1/2(기본 페이지 크기 16KiB에서 8KiB)입니다.
0: https://dev.mysql.com/doc/refman/9.7/en/innodb-row-format.html#innodb-row-format-compressed
정말 흥미롭네요. InnoDB를 알아갈수록 감탄하게 됩니다. 저는 아직 InnoDB 데이터베이스에서 8KiB보다 큰 컬럼 값을 만나 본 적이 없는 것 같아요.
실망할 만한 이유가 몇 가지 있습니다: https://jepsen.io/analyses/mysql-8.0.34
하, blob이나 text 컬럼은 전염병처럼 피하라는 말을 들었는데, 이제 이유를 알겠네요.
제대로 된 DB 스토리지라면 거의 다 LOB/BLOB 같은 골칫덩이를 위한 행 밖 저장 방식이 있어요.
새로운 걸 배우고 그 과정을 공유하는 개인적인 여정을 엿볼 수 있어서 좋았습니다.
다음 단계로는 DuckDB를 써 보시길 권합니다. 이 정도 규모라면 Spark 같은 건 가볍게 압도할 거라고 봅니다. 데이터 세계의 여러 구석을 두루 배워 두면 늘 도움이 되고요.
솔직히 이 작은 여정을 시작한 뒤로 DuckDB 얘기가 계속 나오더라고요.
제가 읽은 글마다 성능이 훨씬 좋아진다는 말씀이 맞다고 하네요 ㅋㅋ 다음에 살펴볼 후보가 될 것 같아요. 감사합니다.
DuckDB는 정말 훌륭합니다.
원래 Python과 Postgres로 구현했던 데이터 분석 처리를 DuckDB로 바꿨는데, 결과에 매우 만족하고 있습니다. Python/Postgres로 6시간 넘게 걸리던 작업이 이제 30분 정도면 끝납니다.
기존 Postgres 데이터베이스에 더하기에도 좋습니다. 네이티브 Postgres 확장과 아주 긴밀하게 통합되어 있어서, Postgres 데이터베이스에서 데이터를 select하고, 로컬에서 DuckDB로 처리한 다음, 다시 Postgres 데이터베이스에 insert하는 식의 작업이 가능합니다.
꼭 한번 써 보시기를 강력히 권합니다.
솔직히 Postgres와 DuckDB는 제대로 손을 더럽혀 가며 배워 보고 싶은 목록에 올라 있어요.
제가 읽은 발표 중에 가장 흥미로웠던 건, 어떤 분이 MySQL의 바이너리 로그로 레이크하우스의 여러 데이터 버전을 미러링하고 DuckDB를 레이크하우스의 컴퓨트 계층으로 썼다는 내용이었어요. 남미에서 열린 발표였던 걸로 기억하는데, 그래서 가 보진 못했네요.
Postgres는 거의 모든 일에 쓸모가 있는 것 같아요 ㅋㅋ 둘이 그렇게 잘 같이 돌아간다니, 둘 다 배워 보는 사이드 프로젝트를 해볼 만하겠어요.