Modül 4 · Veri Ambarı · ⏱ 5 dk

Parquet vs CSV: valiz vs açık bavul

Parquet vs CSV

Bu derste neler öğreneceksin

  • Parquet ın columnar yapısını açıklar
  • Depolama maliyeti karşılaştırması yapar
  • Gerçek dosya boyutlarını ölçer

Storage Format Savaşı

Veriyi diske yazma şeklin, hem performansı hem maliyeti doğrudan etkiler. Üç yaygın formatı karşılaştıralım: CSV (text), JSON (text), Parquet (columnar binary). Her biri farklı senaryo için optimize.

CSV: İnsanların Dostu

Avantajları: Evrensel, herkes okur, Excel/Sheets açar, cat ile bakabilirsin, debug etmek kolay. Dezavantajları: Sütun yok, sıkıştırma yok, type yok, parser yavaş. 1 milyar satır CSV’yi pandas ile okumak GB’larca RAM yer.

CSV genelde sınır geçiş formatı (boundary format). Pipeline’ın bir ucundan diğerine veri taşımak için kullanırsın, ama uzun süreli depolama için değil.

JSON: Yapısal Veri

API’ler JSON konuşur. Yarı yapılandırılmış (semi-structured) veri için iyidir: iç içe objeler, array’ler, opsiyonel alanlar. BigQuery JSON tipi ile bunları doğrudan sorgulayabilir (JSON_VALUE, JSON_QUERY).

SELECT
  JSON_VALUE(payload, '$.user_id') AS user_id,
  JSON_VALUE(payload, '$.event') AS event
FROM events_table;

JSON depolama açısından CSV’den bile kötü: sıkıştırmaz, okunamaz hâle gelir, parse etmek CPU-yorucu.

Parquet: Analytics’in Kralı

Parquet, Apache ekibinin Hadoop dünyasında geliştirdiği columnar binary formattır. Bugün endüstri standardıdır: Spark, BigQuery, Athena, Redshift Spectrum, DuckDB hepsi okur/yazar.

Neden Parquet?

  1. Columnar: Her sütun ayrı dosyada. Sorgu sadece ihtiyacı olan sütunları okur.
  2. Sıkıştırma: Sayısal sütunlar delta encoding + RLE, string sütunlar dictionary encoding ile %70-90 küçülür.
  3. Predicate pushdown: Sütun footer’ında min/max/null count istatistikleri var. Sorgu motoru (BigQuery, DuckDB) “bu aralıkta değer yok” diyerek okumadan atlar.
  4. Row groups: Parquet dosyaları içinde row group’lara bölünür (default 128 MB). Predicate pushdown row group seviyesinde çalışır.
  5. Schema evolution: Yeni sütun eklemek backward-compatible. Eski reader yeni dosyayı okur, yeni sütunları görmezden gelir.

Pratik Karşılaştırma

Python ile aynı NYC taksi verisinin 1 milyon satırını üç formatta yazıp boyut karşılaştırması:

import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
import time

df = pd.read_csv("taxi_sample.csv")  # 1M satır

# CSV
t0 = time.time()
df.to_csv("data.csv", index=False)
print(f"CSV: {time.time()-t0:.2f}s, boyut: ?")

# JSON Lines
t0 = time.time()
df.to_json("data.jsonl", orient="records", lines=True)
print(f"JSONL: {time.time()-t0:.2f}s, boyut: ?")

# Parquet (snappy compression)
t0 = time.time()
df.to_parquet("data.parquet", engine="pyarrow", compression="snappy")
print(f"Parquet: {time.time()-t0:.2f}s, boyut: ?")

# Parquet (zstd - daha iyi sıkıştırma)
t0 = time.time()
df.to_parquet("data.zstd.parquet", engine="pyarrow", compression="zstd")
print(f"Parquet zstd: {time.time()-t0:.2f}s, boyut: ?")

Tipik sonuçlar (1M satır, 18 sütun NYC taksi):

FormatBoyutYazma süresi
CSV~190 MB2.1 s
JSON Lines~280 MB5.8 s
Parquet (snappy)~55 MB0.4 s
Parquet (zstd)~38 MB0.6 s

Parquet, CSV’nin 3-5 kat küçüğü ve yazma hızı 5x. Sıkıştırma seçimi: snappy hız için, zstd boyut için (modern CPU’larda zstd bile hızlı). Genelde snappy yeterli.

BigQuery’de Parquet Nasıl Okunur?

BigQuery external table ile GCS’teki Parquet dosyalarını doğrudan sorgulayabilir, kopyalamadan:

CREATE EXTERNAL TABLE `my_dataset.taxi_external`
OPTIONS (
  format = 'PARQUET',
  uris = ['gs://my-bucket/taxi_data/*.parquet']
);

SELECT COUNT(*) FROM `my_dataset.taxi_external`;

Bu yöntem data lake mimarisinin temelidir: ham veri GCS’te Parquet olarak durur, BigQuery gerektiğinde sorgular. BigQuery’nin kendi Capacitor formatı (native table) daha hızlıdır ama depolama 2x pahalıdır — bu yüzden “sıcak” veri için BigQuery native, “soğuk” veri için Parquet external table yaygın bir pattern’dir.

BigQuery Native Table Yükleme

Bir Parquet dosyasını BigQuery native table’a yüklemek iki yol:

# CLI ile
bq load --source_format=PARQUET my_dataset.taxi data.parquet

# Veya Python ile
from google.cloud import bigquery
client = bigquery.Client()
job = client.load_table_from_uri(
    "gs://my-bucket/data.parquet",
    "my_dataset.taxi",
    job_config=bigquery.LoadJobConfig(source_format=bigquery.SourceFormat.PARQUET)
)
job.result()

BigQuery otomatik olarak Parquet şemasını algılar, sütun tiplerini ayarlar, native Capacitor formatına çevirir (sorgular daha hızlı çalışır).

Production Pattern: Parquet Partitioning

Büyük veri setlerinde Parquet’i partitioned yazmak ek kazanç sağlar. Hive-style partitioning:

gs://my-bucket/taxi/
  year=2024/
    month=01/
      data_2024_01_01.parquet
      data_2024_01_02.parquet
  year=2024/
    month=02/
      data_2024_02_01.parquet

BigQuery external table oluştururken partition’ları otomatik tanır:

CREATE EXTERNAL TABLE `my_dataset.taxi_partitioned`
OPTIONS (
  format = 'PARQUET',
  uris = ['gs://my-bucket/taxi/*'],
  hive_partition_uri_prefix = 'gs://my-bucket/taxi/',
  require_hive_partition_filter = false
);

-- Sorgu sadece 2024 Ocak'ı okur
SELECT * FROM `my_dataset.taxi_partitioned`
WHERE year = 2024 AND month = 1;

Sorgu planında “Bytes processed” sadece o partition’ın boyutunu gösterir. Veri 100x az okunur, sorgu 100x hızlanır, fatura 100x düşer.

Format Seçim Kararı

SenaryoFormat
API’den veri çekiyorsun, henüz işlemedinJSON Lines (geçici)
Pipeline’lar arası veri transferParquet (kalıcı)
BigQuery native tableOtomatik Capacitor
Data lake, archive, düşük erişimParquet + GCS
İnsan okuyacak (debug, Excel)CSV (küçük örnekler)
Streaming event (Kafka)Avro (sonraki modülde)

Ne Öğrendik?

  • Parquet columnar + binary + sıkıştırılmış, analitik için standart.
  • CSV/JSON’dan 3-5x küçük, yazma hızı 5x, okuma hızı 10-100x.
  • Predicate pushdown ile gereksiz satır/sütun hiç okunmaz.
  • BigQuery external table ile GCS’teki Parquet’i kopyalamadan sorgulayabilirsin.
  • Data lake pattern: ham veri Parquet + GCS, sıcak veri BigQuery native.
  • Production’da partitioned Parquet 100x kazanç sağlar.

Sıradaki

Partition & Cluster: BigQuery’de performans optimizasyonu →