컬럼 기반 Parquet 특징 및 성능 비교
✅ 컬럼(Columnar) 기반 저장 특징
- 데이터를 열 단위로 저장하여 분석 쿼리 성능이 빠름
- 컬럼별 압축률이 우수함
- 디스크에서 읽는 데이터의 양을 최소화 (필요한 컬럼만 읽음)
- 분석 및 집계 처리에 최적화 (OLAP 환경에 적합)
✅ 로우(Row) 기반 저장 특징
- 데이터를 행 단위로 저장하여 트랜잭션 처리에 최적화
- 특정 행 전체를 자주 조회할 경우 유리 (OLTP 환경에 적합)
- 그러나 분석용 쿼리에는 불필요한 컬럼까지 읽으므로 성능 저하
Parquet의 컬럼 저장 구조 예시
다음과 같은 테이블이 있다고 가정하겠습니다.
user_id | product_id | purchase_date | price |
1 | 1001 | 2025-03-01 | 3000 |
1 | 1005 | 2025-03-02 | 5000 |
2 | 1003 | 2025-03-01 | 4500 |
3 | 1002 | 2025-03-03 | 2000 |
컬럼 기반 Parquet 저장 방식
반면, Parquet은 아래처럼 각 컬럼을 독립적으로 저장합니다.
[user_id] → [1, 1, 2, 3]
[product_id] → [1001, 1005, 1003, 1002]
[purchase_date] → ["2025-03-01", "2025-03-02", "2025-03-01", "2025-03-03"]
[price] → [3000, 5000, 4500, 2000]
- 데이터를 각 컬럼 단위로 묶어서 저장합니다.
- 컬럼별로 동일한 데이터 타입이기 때문에 압축 효율이 매우 높습니다.
- 특정 컬럼만 읽을 수 있으므로, 조회 대상이 아닌 컬럼은 읽을 필요가 없어 성능이 향상됩니다.
Parquet 저장의 세부적인 내부 구조
Parquet 파일은 내부적으로 Row Group, Column Chunk, Page라는 단위로 저장됩니다.
Parquet 파일
├─ Row Group 1
│ ├─ Column Chunk (user_id)
│ │ └─ [Page: 1, 1, 2, 3]
│ ├─ Column Chunk (product_id)
│ │ └─ [Page: 1001, 1005, 1003, 1002]
│ ├─ Column Chunk (purchase_date)
│ │ └─ [Page: "2025-03-01", "2025-03-02", ...]
│ └─ Column Chunk (price)
│ └─ [Page: 3000, 5000, 4500, 2000]
│
└─ Row Group 2 (더 많은 데이터가 있을 경우)
- Row Group
- Parquet 파일 내 데이터를 나누는 큰 단위입니다.
- 일반적으로 수만~수십만 레코드 단위로 나눕니다.
- Column Chunk
- 각 Row Group 내에서 컬럼별로 데이터를 저장한 단위입니다.
- Page
- Column Chunk 내 데이터를 더 작게 나눈 블록 단위이며, 압축이나 인코딩이 적용되는 최소 단위입니다.
특정 사용자 데이터 추출 시 성능이 좋은 이유
예를 들어, 다음 쿼리를 생각해 보겠습니다
SELECT * FROM table WHERE user_id = 1
Parquet에서의 데이터 접근 프로세스
- 컬럼 선택 (Column Pruning)
✔ user_id 컬럼부터 읽고, 조건(user_id=1)에 해당하는 레코드의 위치를 확인합니다. - 위치 기반 데이터 추출
✔ 조건에 맞는 데이터의 위치(첫 번째, 두 번째 행)를 찾으면, 동일한 위치의 나머지 컬럼만 추가로 읽습니다.
즉, 모든 컬럼을 다 읽지 않아도 되기 때문에 Parquet은 로우 기반 대비 훨씬 빠르게 특정 데이터를 추출할 수 있습니다.
Parquet에서 컬럼 간 데이터 연관 방식
Parquet은 행(row) 위치를 기반으로 컬럼 간 데이터를 연결합니다.
예시 데이터를 다시 보면 다음과 같습니다
행번호 (row index) | user_id | product_id | purchase_date | price |
0 | 1 | 1001 | 2025-03-01 | 3000 |
1 | 1 | 1005 | 2025-03-02 | 5000 |
2 | 2 | 1003 | 2025-03-01 | 4500 |
3 | 3 | 1002 | 2025-03-03 | 2000 |
컬럼 방식으로 저장하면 아래와 같습니다.
[user_id] 컬럼 블록 → [1, 1, 2, 3]
[product_id] 컬럼 블록 → [1001, 1005, 1003, 1002]
[purchase_date] 컬럼 블록 → ["2025-03-01", "2025-03-02", "2025-03-01", "2025-03-03"]
[price] 컬럼 블록 → [3000, 5000, 4500, 2000]
- 각 컬럼의 데이터는 동일한 순서(행 순서)로 저장됩니다.
- 즉, 같은 행에 있는 데이터는 각 컬럼에서 동일한 위치(인덱스)에 위치하게 됩니다.
✅ user_id = 1과 product_id 간의 연관성
예시 쿼리를 다시 보면
SELECT product_id FROM table WHERE user_id = 1;
다음과 같이 추출됩니다.
✅ 처리 과정
- user_id 컬럼을 읽음
[1, 1, 2, 3]
↑ ↑
0번, 1번 인덱스가 조건(user_id=1)에 부합
이후 같은 인덱스의 데이터를 product_id 컬럼에서 읽음
[1001, 1005, 1003, 1002]
↑ ↑
0번 1번
컬럼 기반 저장에서 연관성을 유지하는 원리
- 컬럼 기반 저장은 별도의 레코드 ID나 명시적인 포인터(pointer)가 아니라, 데이터의 위치(index)를 통해 컬럼 간 데이터를 연결합니다.
- Parquet 파일 내부에서 각 컬럼은 독립적으로 저장되지만, 데이터의 순서가 유지됩니다.
(즉, 1번째 user_id 값은 1번째 product_id 값과 연관되는 구조) - 따라서 연관성은 항상 컬럼끼리 동일한 위치(index)를 기준으로 유지됩니다.
컬럼 기반 Parquet에서 사용자 데이터 추출 프로세스 예시
✅ 예시 상황
- 컬럼: user_id, product_id, purchase_date, price
- 목표: 사용자 아이디(user_id)가 1인 모든 구매 이력을 가져오기
✅ 접근방법
① Parquet 파일을 저장한 스토리지에서 필요한 컬럼만 읽음 (predicate pushdown 활용)
② user_id 컬럼에 대한 필터를 적용하여 ID=1인 데이터만 스캔 (column pruning)
③ 필터된 결과를 추출하여 결과셋 생성
# PySpark를 활용한 예시 코드
df = spark.read.parquet("path/to/data.parquet")
result_df = df.filter(df.user_id == 1) # Predicate pushdown 발생
result_df.show()
Parquet의 predicate pushdown이란?
조건절을 스토리지 레벨에서 미리 적용하여, 디스크 I/O와 네트워크 트래픽을 최소화하는 최적화 방식입니다.
로우 기반과 컬럼 기반 성능 비교 요약
항목 | 컬럼 기반(Parquet) | 로우 기반(CSV, Avro 등) |
조회 유형 | 분석, 필터링 및 집계에 유리 | 트랜잭션 기반 전체 행 조회에 유리 |
디스크 읽기 성능 | 필요한 컬럼만 읽어 속도가 빠름 | 전체 행을 읽어 속도 느림 |
압축 효율성 | 매우 우수 | 상대적으로 낮음 |
I/O 성능 | 높음 | 낮음 |
용도 | 데이터 분석, DW, OLAP 적합 | OLTP 및 트랜잭션 처리에 적합 |
Apache Parquet, 컬럼 기반의 저장 방식
데이터가 폭발적으로 증가하는 시대, 우리는 데이터를 보다 효율적으로 저장하고 빠르게 분석할 수 있는 방법이 필요합니다. Apache Parquet은 이러한 요구를 충족하는 강력한 컬럼 기반 저장 형식(
make2t.tistory.com
'IT > 데이터' 카테고리의 다른 글
📘 데이터 거래사 자격증이란? (1) | 2025.04.04 |
---|---|
Apache Hive란? 빅데이터 분석을 위한 강력한 SQL 기반 데이터 웨어하우스 (1) | 2025.03.21 |
Apache Parquet, 컬럼 기반의 저장 방식 (1) | 2025.03.17 |
데이터 명명규칙 가이드: 단어, 용어, 도메인 표준화 정리 (5) | 2025.03.16 |
벡터 데이터베이스 (1) | 2025.03.04 |