데이터 분석을 하다 보면 "그냥 CSV로 저장하면 되지, 왜 굳이 Parquet를 쓰지?"라는 의문이 들 때가 있습니다. 둘 다 표 형태 데이터를 담는 파일인데, 한쪽은 메모장으로도 열리고 한쪽은 그렇지도 않으니 더 그렇습니다.
그렇다면 정확히 무엇이 다를까요. 용량은 얼마나 줄고, 읽는 속도는 얼마나 빨라질까요. 말로만 "Parquet가 효율적"이라고 하기보다, 같은 데이터를 두 형식으로 저장해 직접 재 봤습니다.
10만 행을 직접 만들어 두 형식으로 저장했습니다
숫자 컬럼과 반복되는 문자 컬럼을 섞은 10만 행 데이터를 만들었습니다. 컬럼은 6개입니다. id(연번), amount(금액), score(점수), 그리고 도시, 등급, 부서처럼 같은 값이 계속 반복되는 범주형 문자 컬럼 3개입니다. 실제 업무 데이터와 비슷한 구성입니다.
측정 환경은 윈도우 11, 파이썬 3.14.3, pandas 3.0.1, pyarrow 24.0.0입니다. Parquet 저장 엔진은 pyarrow를 썼습니다.
| 저장 형식 | 파일 크기 | CSV 대비 |
|---|---|---|
| CSV (data.csv) | 약 3.46 MB | 1.00배 |
| Parquet (data.parquet) | 약 1.54 MB | 0.44배 |
같은 10만 행인데 Parquet 파일이 CSV의 절반 이하입니다. 정확히는 CSV가 3,633,263 바이트, Parquet가 1,616,651 바이트로 CSV가 Parquet보다 약 2.25배 큽니다.
읽는 속도는 더 벌어집니다
용량만 차이 나는 게 아닙니다. 두 파일을 pandas로 불러오는 시간을 여러 번 재서 평균을 냈습니다. 같은 데이터를 같은 횟수로 읽었습니다.
| 작업 | 평균 읽기 시간 |
|---|---|
| read_csv | 약 0.33초 |
| read_parquet | 약 0.03초 |
Parquet 읽기가 대략 10배가량 빨랐습니다. CSV는 글자로 적힌 숫자를 한 칸씩 다시 숫자로 해석하며 읽어야 하지만, Parquet는 데이터를 이미 형식과 자료형이 정해진 덩어리로 저장해 두기 때문입니다. 읽기 시간의 정확한 배율은 실행할 때마다 5배에서 12배 사이로 흔들렸지만, Parquet가 빠른 방향은 매번 같았습니다.
왜 Parquet가 작고 빠를까
핵심은 저장하는 방향이 다르다는 데 있습니다. CSV는 한 줄에 한 행을 통째로 적는 행 기반 저장입니다. 반면 Parquet는 같은 컬럼의 값끼리 모아서 적는 열 기반 저장입니다.
열 기반으로 모으면 압축이 잘 듣습니다. 예를 들어 도시 컬럼에 "서울"이 수천 번 나오면, Parquet는 이걸 일일이 다 적는 대신 "서울이라는 값이 여기 몇 번"이라는 식으로 압축해 둡니다. 같은 값이 많이 반복될수록 효과가 큽니다. 이번 데이터의 도시, 등급, 부서 컬럼이 바로 그런 반복 컬럼이라 용량이 크게 줄었습니다.
속도도 같은 이유입니다. 숫자 컬럼은 처음부터 숫자 자료형으로 저장돼 있어, 읽을 때 글자를 숫자로 바꾸는 변환 과정이 거의 없습니다.
그런데 항상 절반이 되는 건 아닙니다
여기서 중요한 단서가 있습니다. Parquet의 압축 이득은 데이터에 반복이 많을 때 크게 나타납니다. 반복이 거의 없는 데이터라면 차이가 확 줄어듭니다.
이걸 확인하려고, 반복이 거의 없는 데이터로 다시 재 봤습니다. 컬럼을 연번, 무작위 큰 정수, 그리고 매 행이 전부 다른 12자리 무작위 문자열로 바꿨습니다.
| 데이터 종류 | CSV | Parquet | CSV 대비 |
|---|---|---|---|
| 반복 많은 범주형 포함 | 약 3.46 MB | 약 1.54 MB | 2.25배 |
| 거의 무작위(반복 없음) | 약 2.84 MB | 약 2.82 MB | 1.01배 |
무작위 데이터에서는 CSV와 Parquet 크기가 거의 같았습니다(2,977,793 vs 2,954,886 바이트). 압축할 반복이 없으니 열로 모아도 줄일 거리가 없는 것입니다. Parquet의 용량 이득은 데이터에 반복이 얼마나 많은지에 크게 좌우됩니다.
직접 확인하고 싶다면
아래 코드를 그대로 실행하면 위와 같은 10만 행 데이터를 만들고 두 형식으로 저장해 크기와 읽기 시간을 출력합니다. pandas와 pyarrow가 설치돼 있어야 합니다.
import os, time, random
import pandas as pd
random.seed(42)
N = 100000
cities = ["서울","부산","대구","인천","광주","대전","울산","수원","성남","고양"]
grades = ["A","B","C","D"]
depts = ["영업","개발","디자인","인사","재무","마케팅","운영","기획"]
df = pd.DataFrame({
"id": range(1, N+1),
"amount": [random.randint(1000, 999999) for _ in range(N)],
"score": [round(random.uniform(0, 100), 2) for _ in range(N)],
"city": [random.choice(cities) for _ in range(N)],
"grade": [random.choice(grades) for _ in range(N)],
"dept": [random.choice(depts) for _ in range(N)],
})
df.to_csv("data.csv", index=False, encoding="utf-8")
df.to_parquet("data.parquet", engine="pyarrow")
print("CSV :", os.path.getsize("data.csv"), "bytes")
print("Parquet:", os.path.getsize("data.parquet"), "bytes")
def avg_read(fn, reps=10):
ts = []
for _ in range(reps):
t0 = time.perf_counter(); fn(); ts.append(time.perf_counter()-t0)
return sum(ts) / len(ts)
print("read_csv :", round(avg_read(lambda: pd.read_csv("data.csv")), 3), "s")
print("read_parquet :", round(avg_read(lambda: pd.read_parquet("data.parquet")), 3), "s")
seed를 42로 고정했기 때문에 같은 환경이면 비슷한 크기가 나옵니다. 읽기 시간은 컴퓨터 사양과 그때그때 상태에 따라 달라지므로, 절대 시간보다는 두 형식의 상대 차이를 보시면 됩니다.
그래서 언제 무엇을 쓰면 될까
| 이럴 때 | 이 형식 |
|---|---|
| 엑셀이나 메모장으로 바로 열어 보고 싶을 때 | CSV |
| 다른 사람과 가볍게 주고받거나 호환성이 가장 중요할 때 | CSV |
| 같은 데이터를 반복해서 읽고 분석할 때 | Parquet |
| 수십만 행 이상으로 용량과 속도가 부담될 때 | Parquet |
CSV는 어디서나 열리는 범용성이 강점이고, Parquet는 대용량을 빠르고 작게 다루는 분석용 형식입니다. 작은 데이터를 한 번 보고 말 거라면 CSV로 충분하고, 같은 데이터를 매번 불러와 가공한다면 Parquet로 바꿔 두는 편이 시간과 저장공간을 아껴 줍니다.
같은 데이터라도 어떻게 저장하느냐에 따라 용량과 속도가 이만큼 갈립니다. 내 데이터에 같은 값이 자주 반복되고 자주 읽을 일이 많다면, CSV 대신 Parquet를 한번 시험해 볼 만합니다.
'파일 형식 백과사전' 카테고리의 다른 글
| JSON "Expecting property name", "Expecting ',' delimiter" 오류, 증상별로 원인 찾고 고치기 (0) | 2026.07.05 |
|---|---|
| CSV를 Parquet로 변환하기, 특별한 프로그램 없이 pandas 한 줄이면 됩니다 (1) | 2026.07.04 |
| CSV를 UTF-8로 저장하는 법, 엑셀과 메모장과 파이썬에서 각각 (0) | 2026.07.02 |
| JSON 한 줄 저장과 들여쓰기 저장, 용량이 얼마나 차이 날까 (실측과 정리 방법) (0) | 2026.06.30 |
| 아이폰 사진 수백 장이 HEIC일 때, PC에서 한 번에 JPG로 바꾸는 법 (0) | 2026.06.29 |