LUVIT♥ EPL과 유튜브 데이터로 배우는 DuckDB | 이기준
DuckDB를 활용한 SQL 기반 데이터 분석 입문서다. SQL 기초부터 고급 활용, 파이썬 연동, 데이터 시각화와 대시보드 제작까지 단계적으로 학습할 수 있다. EPL 데이터, 유튜브 트렌드, 「케이팝 데몬
www.aladin.co.kr
수 기가바이트 규모의 파일 때문에 컴퓨터가 멈추는 일을 피하는 방법 — Spark도, 클러스터도, IT 부서도 필요 없다.
여러분도 한 번쯤은 겪어보셨을 법한 상황입니다.
이런 상황을 떠올려 보시기 바랍니다. 며칠 안에 처리해야 할 데이터 추출 파일을 받았습니다. 크기는 4.2GB짜리 CSV 파일이며, 수백만 건의 고객 거래 내역이 들어 있습니다. 요청 사항은 한 문장으로 요약됩니다. 중복 데이터를 찾아 표시하고, 이를 마스터 목록과 대조한 뒤, 국가별 요약 결과를 만들어 달라는 것입니다.
아마도 가장 먼저 떠오르는 반응은 이것일 것입니다.
import pandas as pd
df = pd.read_csv("transactions.csv")
30초가 지나고, 1분이 지나고, 2분이 지납니다. 그리고 대부분의 분석가가 한 번쯤은 보았을 메시지가 나타납니다.
MemoryError
RAM 16GB를 장착한 컴퓨터가 오후 안에 분석을 끝내야 하는 파일 하나를 처리하지 못하고 포기해 버린 것입니다.
이것은 특별한 예외 상황이 아닙니다. 이제는 오히려 일상이 되었습니다. 청구 데이터, 업무용 내보내기 파일, 품질 관리 데이터 등 모든 데이터는 계속해서 커지고 있습니다. 그런데 우리의 작업 방식은 그 변화를 따라가지 못하고 있습니다.
바로 이런 벽에 부딪히면서 저는 DuckDB를 진지하게 보기 시작했습니다. 단순히 또 하나의 유행 기술이 아니라, 아주 현실적인 문제에 대한 실용적인 해답으로 말입니다. 아래는 누군가가 더 일찍 알려주었으면 좋았을 내용들입니다.
Pandas가 결국 한계에 부딪히는 이유
Pandas는 훌륭한 도구입니다. 저 역시 지금도 매일 사용하고 있습니다. 하지만 쉽게 잊기 쉬운 결정적인 특징이 하나 있습니다. 바로 데이터를 한 번에 모두 메모리로 불러온다는 점입니다.
4GB 파일에 대해 pd.read_csv()를 실행하면 Pandas는 "필요한 부분만" 읽지 않습니다. 파일 전체를 압축 해제하고, 파싱하고, 메모리에 객체로 생성합니다. Python 데이터 타입과 내부 자료구조 때문에 실제 메모리 사용량은 원본 크기의 2~3배에 달하는 경우가 많습니다. 4GB CSV 파일 하나를 불러오는 데도 분석 코드를 한 줄도 작성하기 전에 10~12GB의 메모리가 필요할 수 있습니다.
결과는 충분히 예상 가능합니다.
- 끝없이 이어지는 로딩 시간
- 컴퓨터 한계까지 치솟는 메모리 사용량
- 프로그램 강제 종료
- 작업보다 도구를 기다리는 데 더 많은 시간을 쓰게 되는 답답함
더 황당한 점은 대부분의 경우 파일 전체가 필요하지 않다는 것입니다. 특정 국가의 데이터만 필요하거나, 40개 컬럼 중 3개만 필요하거나, 단 하나의 집계 결과만 필요할 수도 있습니다. 그런데 Pandas는 그 모든 데이터를 전부 불러옵니다.
DuckDB를 2분 만에 이해하기
DuckDB는 분석용 데이터베이스입니다. 하지만 데이터베이스라는 단어를 들었을 때 떠오르는 이미지는 잠시 잊어도 됩니다.
설치해야 할 서버도 없습니다. 구성해야 할 클러스터도 없습니다. 관리자를 찾을 필요도 없습니다. DuckDB는 일반적인 Python 라이브러리처럼 설치됩니다.
pip install duckdb
그리고 여러분의 코드와 같은 프로세스 안에서, 같은 컴퓨터에서 실행됩니다. 많은 사람들이 DuckDB를 "분석용 SQLite"라고 부르는데, 꽤 적절한 표현입니다. DuckDB는 필터링, 집계, 대용량 조인과 같은 분석 쿼리를 위해 설계된 매우 빠른 SQL 엔진입니다.
처음 사용했을 때 가장 인상적인 점은 CSV나 Parquet 파일을 별도의 적재 과정 없이 직접 읽을 수 있다는 것입니다.
import duckdb
duckdb.sql("""
SELECT country, COUNT(*) AS n
FROM 'transactions.csv'
GROUP BY country
""").df()
Pandas를 멈추게 만들었던 4GB CSV 파일도 DuckDB에서는 메모리를 한계까지 사용하지 않으면서 몇 초 만에 국가별 집계 결과를 반환합니다. 이 차이는 단순히 조금 더 빠른 수준이 아닙니다. 데이터를 다루는 방식 자체를 바꾸어 놓습니다.
실제로 체감되는 기능들
1. 파일 전체를 메모리에 적재하지 않고 읽기
이것이 핵심입니다. DuckDB는 Predicate Pushdown이라 불리는 기술을 사용합니다. 즉, 필터 조건을 가능한 한 파일 읽기 단계에 가깝게 적용하여 필요한 데이터만 가져옵니다.
# €10,000 초과의 프랑스 거래만 조회
duckdb.sql("""
SELECT *
FROM 'transactions.csv'
WHERE country = 'FR' AND amount > 10000
""").df()
DuckDB는 파일을 스캔하면서 동시에 필터를 적용하고, 조건에 맞는 행만 메모리에 생성합니다. Pandas가 4GB 전체를 읽어들인 뒤 그중 2%만 사용하는 방식이라면, DuckDB는 필요한 데이터만 처리합니다.
2. 여러 파일을 한 번에 읽기
실제 업무에서는 데이터가 여러 파일로 나뉘어 전달되는 경우가 많습니다. 월별, 기관별, 국가별로 파일이 분리되어 있는 경우가 대표적입니다.
duckdb.sql("""
SELECT *
FROM 'exports/transactions_2025_*.csv'
""").df()
*(glob) 패턴을 사용하면 조건에 맞는 모든 파일을 하나의 테이블처럼 읽을 수 있습니다. 더 이상 pd.concat()을 반복 호출하는 루프를 작성하면서 메모리 문제를 걱정할 필요가 없습니다.
3. SQL만 사용하면 된다
분석, 보고서 작성, 데이터 검증 업무를 해왔다면 이미 SQL에 익숙할 가능성이 높습니다. DuckDB를 사용하면 읽기 쉽고, 재현 가능하며, 동료가 검토하기도 쉬운 쿼리를 작성할 수 있습니다.
특히 분석 결과만큼 분석 과정의 추적 가능성이 중요한 프로젝트에서는 이것이 큰 장점이 됩니다.
4. Pandas와의 자연스러운 통합
DuckDB는 Pandas를 대체하는 도구가 아니라 보완하는 도구입니다. Pandas DataFrame을 SQL 테이블처럼 직접 조회할 수 있습니다.
import pandas as pd
import duckdb
df = pd.read_excel("billing.xlsx")
# DuckDB가 Pandas DataFrame을 테이블처럼 읽음
duckdb.sql("""
SELECT client, SUM(amount) AS total
FROM df
GROUP BY client
HAVING total > 50000
""").df()
결국 가장 좋은 작업 방식은 적절한 순간에 적절한 도구를 사용하는 것입니다. 무거운 연산은 DuckDB가 담당하고, 최종 가공과 후처리는 Pandas가 담당하도록 역할을 나누는 것입니다.
대용량 Excel 파일의 함정
솔직히 말해 보겠습니다. 기업 환경에서는 Excel이 어디에나 있습니다. 비즈니스 부서가 보내주는 기본 파일 형식이기 때문입니다. Parquet가 아니라 .xlsx 파일입니다.
문제는 수십만 행만 되어도 Excel 파일이 금방 다루기 어려워진다는 점입니다. 열리는 데 오래 걸리고, 수식 계산은 느려지며, 파일이 멈추거나 응답하지 않는 경우도 흔합니다. Python에서도 마찬가지입니다. pd.read_excel()은 CSV를 읽는 것보다 눈에 띄게 느립니다.
DuckDB는 확장 기능을 통해 Excel 파일을 직접 읽을 수 있습니다.
import duckdb
duckdb.sql("INSTALL excel; LOAD excel;")
duckdb.sql("""
SELECT *
FROM read_xlsx('controls.xlsx', sheet = 'Data')
WHERE status = 'INCOMPLETE'
""").df()
이 경우 DuckDB는 중간 계층 역할을 합니다. 다루기 어려운 Excel 파일을 받아들인 뒤 SQL을 사용하여 필터링, 집계, 대조 작업을 수행할 수 있으며, Excel 파일을 직접 열 필요조차 없습니다.
하지만 진짜 효과는 그 다음 단계에서 나타납니다.
모든 분석가가 알아야 할 활용 사례: Excel → Parquet
이 글에서 단 한 가지만 기억해야 한다면, 바로 이것입니다.
Parquet란 무엇인가?
Parquet는 분석을 위해 설계된 파일 형식입니다. CSV나 Excel이 데이터를 행(Row) 단위로 저장하는 것과 달리, Parquet는 열(Column) 단위로 저장합니다. 언뜻 보면 사소해 보이는 차이지만, 이것이 모든 것을 바꿔 놓습니다.
왜 Parquet가 표준이 되었을까?
압축 효율
Parquet는 매우 높은 압축률을 제공합니다. 4GB 크기의 CSV 파일은 보통 400~800MB 크기의 Parquet 파일로 변환됩니다. 즉, 5배에서 10배 정도 더 작아집니다. 디스크 공간, 백업 저장소, 파일 전송 비용 모두 절약할 수 있습니다.
속도
Parquet는 데이터 타입이 명확하게 정의된 구조화된 형식입니다. 매번 텍스트를 파싱할 필요가 없고, 데이터 타입을 추론할 필요도 없습니다. 숫자는 항상 숫자로 저장됩니다. 따라서 읽기 속도가 훨씬 빠릅니다.
필요한 컬럼만 읽기
이것이 가장 중요한 장점입니다. 40개 컬럼 중 3개 컬럼만 필요하다면 Parquet는 해당 3개 컬럼만 디스크에서 읽습니다. 반면 CSV는 원하는 컬럼을 얻기 위해 전체 파일을 모두 읽어야 합니다. 대용량 파일에서는 그 차이가 몇 배가 아니라 몇십 배에 이를 수 있습니다.
작업 흐름
Excel / CSV
↓
DuckDB
↓
Parquet
↓
Python / Power BI / Analytics
아이디어는 간단합니다. 무거운 Excel 또는 CSV 파일을 한 번만 Parquet로 변환한 뒤, 이후의 모든 분석 작업은 Parquet 파일을 기반으로 수행하는 것입니다.
단 한 번의 쿼리로 변환하기
import duckdb
# CSV → Parquet
duckdb.sql("""
COPY (SELECT * FROM 'transactions.csv')
TO 'transactions.parquet' (FORMAT PARQUET)
""")
# Excel → Parquet
duckdb.sql("INSTALL excel; LOAD excel;")
duckdb.sql("""
COPY (SELECT * FROM read_xlsx('billing.xlsx'))
TO 'billing.parquet' (FORMAT PARQUET)
""")
이것으로 끝입니다. 단 한 번의 쿼리만으로 다루기 어려웠던 파일이 가볍고 빠른 분석용 파일로 바뀝니다.
실제로 얻는 이점
Parquet로 변환한 후에는 쿼리 성능이 크게 향상됩니다.
# Parquet 파일에서는 amount 컬럼만 읽음
duckdb.sql("""
SELECT AVG(amount), MAX(amount)
FROM 'transactions.parquet'
""").df()
Power BI에서도 큰 장점이 있습니다. Power BI는 Parquet를 기본적으로 지원하므로 새로 고침 속도가 빨라지고 데이터 모델도 가벼워집니다. 매번 수백 MB 크기의 CSV 파일을 불러오며 새로 고침 시간을 기다릴 필요가 없습니다.
이론이 아닌 실제 사례
DuckDB의 진가는 실제 업무 환경에서 더욱 잘 드러납니다. 아래는 규모가 큰 데이터셋이라면 어디에서나 적용할 수 있는 대표적인 사례들입니다.
중복 송장 찾기
가장 흔한 질문 중 하나는 동일한 송장이 두 번 지급되었는지 확인하는 것입니다.
duckdb.sql("""
SELECT vendor,
amount,
invoice_date,
COUNT(*) AS occurrences
FROM 'invoices.parquet'
GROUP BY vendor, amount, invoice_date
HAVING COUNT(*) > 1
ORDER BY occurrences DESC
""").df()
수백만 건의 데이터에서도 몇 초 안에 잠재적인 중복 송장 목록을 확인할 수 있습니다. Pandas에서도 가능하지만, 더 복잡하고 느린 스크립트가 필요할 가능성이 높습니다.
다국가 데이터 분석
여러 국가를 대상으로 하는 프로젝트에서는 국가별 규모를 파악하고 이상치를 확인해야 하는 경우가 많습니다.
duckdb.sql("""
SELECT country,
COUNT(*) AS n_operations,
SUM(amount) AS total_volume,
AVG(amount) AS avg_amount
FROM 'operations/*.parquet'
GROUP BY country
ORDER BY total_volume DESC
""").df()
* 패턴을 사용하면 국가별로 분리된 모든 파일을 한 번에 집계할 수 있습니다. 반복문도 필요 없고 수동 병합도 필요 없습니다.
마스터 데이터의 완전성 점검
필수 정보가 누락된 레코드를 찾는 작업도 간단합니다.
duckdb.sql("""
SELECT
COUNT(*) AS total,
COUNT(*) FILTER (WHERE birth_date IS NULL) AS missing_birth_date,
COUNT(*) FILTER (WHERE id_document IS NULL) AS missing_id_document,
COUNT(*) FILTER (WHERE country IS NULL) AS missing_country
FROM 'master_data.parquet'
""").df()
파일을 한 번만 읽으면서 모든 품질 지표를 계산할 수 있습니다. 데이터 품질 보고서나 감사 대응 자료를 만들기에 매우 적합합니다.
왜 이런 작업에 DuckDB가 잘 맞을까?
추적 가능성
SQL 쿼리는 읽기 쉽고 재현 가능합니다. 다른 사람이 검토하고 동일한 결과를 다시 생성할 수 있습니다. 분석 과정을 문서화해야 하는 상황에서는 매우 중요한 장점입니다.
대용량 데이터 처리
실무 데이터는 종종 매우 큽니다. DuckDB는 이런 규모의 데이터 처리에 최적화되어 있습니다.
보안과 기밀성
모든 작업이 사용자의 컴퓨터에서 로컬로 수행됩니다. 민감한 데이터를 외부 서비스나 서버로 전송할 필요가 없습니다.
빠른 반복 작업
분석 업무는 가설을 세우고 검증하는 과정을 반복합니다. 검증 결과를 몇 초 안에 확인할 수 있다는 것은 업무 속도 자체를 바꾸어 놓습니다.
Spark의 가벼운 대안
이 질문에는 솔직하게 답할 필요가 있습니다. 거의 항상 등장하는 질문이기 때문입니다.
“그렇다면 Spark를 쓰면 되지 않나요?”
Spark는 분산 컴퓨팅 도구입니다. 여러 대의 컴퓨터로 구성된 클러스터에 작업을 분산시키는 것이 핵심 강점입니다. 데이터가 단일 컴퓨터에 들어가지 않을 정도로 큰 경우, 즉 수 테라바이트 규모의 데이터나 대규모 분산 파이프라인에서는 반드시 필요한 도구입니다.
하지만 대부분의 팀이 결국 인정하는 현실이 있습니다. 상당수의 “빅데이터” 프로젝트는 사실 빅데이터가 아닙니다. 몇 GB 규모의 데이터는 빅데이터가 아닙니다. 적절한 도구만 사용한다면 최신 노트북에서도 충분히 처리할 수 있는 대용량 데이터일 뿐입니다.
DuckDB만으로 충분한 경우
다음과 같은 상황이라면 DuckDB만으로도 충분합니다.
- 수백 MB에서 수십 GB 규모의 파일을 다룰 때
- 혼자 또는 소규모 팀에서 분석 작업을 수행할 때
- 별도의 인프라 없이 빠르게 작업하고 싶을 때
- 데이터 탐색, 보고서 작성, 데이터 검증, 애드혹 분석을 수행할 때
이러한 경우, 즉 데이터 분석가 업무의 대부분에서는 DuckDB만으로 충분하며 클러스터 운영의 복잡성까지 떠안을 필요가 없습니다.
여전히 Spark가 필요한 경우
반면 다음과 같은 상황에서는 Spark가 적합합니다.
- 데이터 규모가 단일 컴퓨터의 처리 한계를 초과할 때
- 분산 처리와 장애 복구 기능이 필수일 때
- 매우 큰 규모의 프로덕션 파이프라인을 운영할 때
- 여러 팀이 공통 컴퓨팅 인프라를 공유할 때
중요한 것은 "기본적으로 Spark를 선택하는 것"이 아닙니다. 올바른 접근 방식은 가능한 한 단순하게 시작하고, 데이터 규모가 정말 필요로 할 때만 복잡성을 추가하는 것입니다.
5GB 데이터를 처리하기 위해 Spark 클러스터를 구축하는 것은 못 하나를 박기 위해 대형 해머를 꺼내 드는 것과 같습니다.
DuckDB의 한계
완벽한 도구는 없습니다. 그리고 한계에 대해 솔직하게 이야기할 때 비로소 신뢰할 수 있는 평가가 됩니다.
- 트랜잭션 데이터베이스가 아닙니다. DuckDB는 읽기와 집계 같은 분석 작업을 위해 설계되었습니다. PostgreSQL처럼 수천 건의 동시 쓰기 작업을 처리하는 용도로 만들어진 데이터베이스가 아닙니다.
- 단일 컴퓨터 기반입니다. 하나의 컴퓨터가 처리할 수 있는 한계를 넘어서는 규모라면 DuckDB는 더 이상 적합한 선택이 아닙니다. 그때는 Spark나 데이터 웨어하우스가 필요합니다.
- 상대적으로 젊은 생태계입니다. 빠르게 성장하고 있지만 Pandas나 Spark에 비하면 튜토리얼, 예제, 커뮤니티 자료는 아직 적은 편입니다.
- Pandas를 완전히 대체하지는 못합니다. 세밀한 데이터 조작, 행 단위 정제 작업, 시각화, 머신러닝에서는 여전히 Pandas와 그 생태계가 필수적입니다.
올바른 관점은 DuckDB를 모든 것을 대체하는 도구가 아니라, 분석가의 도구 상자에 추가할 강력한 도구로 보는 것입니다.
실무적인 결론
저는 Pandas를 버리지 않았습니다. 그렇다고 Spark 클러스터를 구축하지도 않았습니다. 단지 원본 파일과 분석 작업 사이에 하나의 계층을 추가했을 뿐입니다.
새로운 작업 방식은 다음과 같습니다.
대용량 파일 도착 (CSV, Excel 등)
↓
DuckDB
↓
Parquet로 변환
↓
SQL로 필터링 · 집계 · 검증
↓
Pandas 또는 Power BI로 마무리
가장 크게 달라진 점은 무엇일까요?
더 이상 도구가 끝나기를 기다리지 않는다는 것입니다.
예전에는 컴퓨터를 멈추게 만들던 파일들이 이제는 몇 초 만에 처리됩니다. 시간이 부족하고, 분석 과정의 추적 가능성까지 요구되는 환경에서는 이러한 차이를 매일 체감하게 됩니다.
대용량 파일을 자주 다루고 있고 Pandas가 버거워하는 모습을 자주 본다면, 오늘 오후에 직접 한 번 테스트해 보시기 바랍니다. 설치는 한 줄이면 끝나고, 첫 번째 쿼리는 5분 안에 실행할 수 있습니다.
이 정도로 빠르게 가치를 보여주는 도구는 생각보다 많지 않습니다.
TL;DR
- Pandas는 데이터를 전부 메모리로 불러오기 때문에 대용량 파일에서는 메모리 부족이나 성능 저하가 발생합니다. DuckDB는 쿼리에 필요한 데이터만 읽습니다.
- DuckDB는 pip install duckdb 한 줄로 설치되며 서버나 클러스터 없이 로컬 컴퓨터에서 실행됩니다.
- CSV, Excel, Parquet 파일을 직접 읽을 수 있으며 Pandas DataFrame도 SQL로 조회할 수 있습니다.
- 대용량 파일은 Parquet로 변환하는 것이 좋습니다. 파일 크기는 5~10배 작아지고 읽기 속도는 크게 향상되며 필요한 컬럼만 선택적으로 읽을 수 있습니다. Power BI와도 매우 잘 어울립니다.
- 중복 데이터 탐지, 국가별 분석, 데이터 완전성 점검과 같은 작업을 읽기 쉽고 재현 가능한 SQL로 수행할 수 있습니다.
- 수 GB 규모의 데이터라면 대부분 Spark가 필요하지 않습니다. Spark는 테라바이트 규모의 분산 처리 환경에 남겨 두는 것이 좋습니다.
- DuckDB의 한계는 단일 컴퓨터 기반이라는 점, 트랜잭션 처리에 적합하지 않다는 점, 그리고 아직 생태계가 상대적으로 작다는 점입니다. 따라서 대체재가 아니라 보완재로 사용하는 것이 가장 효과적입니다.
여러분은 이미 자신의 데이터 추출 파일에 DuckDB를 사용해 보셨나요? 어떤 용도로 활용하고 있는지 궁금합니다.
'EPL과 유튜브 데이터로 배우는 DuckDB' 카테고리의 다른 글
| DuckDB의 더 친숙한 SQL - Part 4 (0) | 2026.06.07 |
|---|---|
| DuckDB와 AI로 대용량 데이터셋 분석하기: 초보자 가이드 (0) | 2026.06.07 |
| DuckDB의 더 친숙한 SQL - Part 3 (0) | 2026.06.06 |
| DuckDB의 더 친숙한 SQL - Part 2 (0) | 2026.06.05 |
| DuckDB의 더 친숙한 SQL - Part 1 (0) | 2026.06.04 |
댓글