Schema adalah bentuk fisik data time-series saat disimpan. Topik ini membandingkan dua bentuk, yaitu schema sempit (narrow) dengan satu pengukuran per baris dan schema lebar (wide) dengan banyak kolom terukur. Setelah membaca, keputusan bentuk tidak lagi diambil karena kebetulan, melainkan karena beban yang dipikulnya dapat disebutkan secara eksplisit.
Dua bentuk yang sama sekali berbeda#
Schema sempit menyimpan satu pasangan nama dan nilai pengukuran pada setiap baris, sehingga sebuah stasiun cuaca yang melaporkan suhu, kelembapan, dan tekanan pada cap waktu yang sama menghasilkan tiga baris terpisah. Kolom pada schema ini biasanya terdiri atas cap waktu, identitas seri seperti station_id, nama pengukuran, dan nilai. Schema lebar menyimpan seluruh pengukuran pada satu cap waktu sebagai satu baris, sehingga stasiun yang sama menghasilkan satu baris dengan tiga kolom nilai yang berbeda. Pilihan ini tampak sekadar rotasi tabel, tetapi keduanya menyiratkan beban penyimpanan dan pola query yang berbeda.
Schema sempit unggul ketika daftar pengukuran berubah seiring waktu. Penambahan metrik tekanan cukup berupa baris baru dengan metric='tekanan', tanpa perubahan struktur. Schema lebar unggul ketika daftar pengukuran tetap dan padat, sebab satu baris menyimpan banyak nilai sekaligus, sehingga pemindaian query rentang waktu menjadi lebih efisien. Schema sempit menambah tiga kali lipat baris pada contoh di atas, sedangkan schema lebar menambah kolom. Banyaknya baris memengaruhi ukuran indeks dan kompresi, sedangkan banyaknya kolom memengaruhi lebar chunk dan kelincahan query agregat.
Konversi antar schema dengan pandas#
pandas menyediakan operasi melt untuk membongkar schema lebar menjadi sempit dan pivot untuk sebaliknya. Skrip berikut membangkitkan empat baris schema lebar dari dua stasiun cuaca, lalu mengubahnya menjadi schema sempit dan kembali ke schema lebar untuk memverifikasi bahwa konversi bersifat reversibel. Skrip juga mencatat dimensi tiap bentuk, sehingga perbedaan jumlah baris dan kolom menjadi nyata.
"""Perbandingan schema sempit vs lebar pada data time-series.
Skrip membangkitkan telemetri stasiun cuaca dalam bentuk schema lebar,
lalu mengubahnya menjadi schema sempit dengan operasi melt dan kembali
ke schema lebar dengan pivot. Tujuannya menunjukkan bahwa kedua bentuk
adalah rotasi tabel yang sama, tetapi menyiratkan beban penyimpanan dan
pola query yang berbeda.
"""
from __future__ import annotations
import pandas as pd
STASIUN = ["STA01", "STA02"]
CAP_WAKTU = pd.to_datetime([
"2026-11-01 00:00:00",
"2026-11-01 00:15:00",
])
def bangun_lebar() -> pd.DataFrame:
return pd.DataFrame({
"ts": list(CAP_WAKTU) * len(STASIUN),
"station_id": [s for s in STASIUN for _ in CAP_WAKTU],
"suhu_c": [24.1, 24.4, 22.8, 23.0],
"kelembapan": [62.0, 61.5, 70.2, 69.8],
"tekanan_hpa": [1013.2, 1013.1, 1012.8, 1012.9],
})
def lebar_ke_sempit(df: pd.DataFrame) -> pd.DataFrame:
return df.melt(
id_vars=["ts", "station_id"],
var_name="metric",
value_name="nilai",
)
def sempit_ke_lebar(df: pd.DataFrame) -> pd.DataFrame:
return df.pivot_table(
index=["ts", "station_id"],
columns="metric",
values="nilai",
).reset_index()
def main() -> None:
lebar = bangun_lebar()
sempit = lebar_ke_sempit(lebar)
lebar_lagi = sempit_ke_lebar(sempit)
print("schema lebar (1 baris per stasiun per cap waktu):")
print(lebar.to_string(index=False))
print()
print(f" dimensi: {lebar.shape[0]} baris x {lebar.shape[1]} kolom")
print()
print("schema sempit (1 baris per pengukuran):")
print(sempit.to_string(index=False))
print()
print(f" dimensi: {sempit.shape[0]} baris x {sempit.shape[1]} kolom")
print()
print("schema lebar hasil konversi ulang:")
lebar_lagi.columns.name = None
print(lebar_lagi.to_string(index=False))
print()
print(f" dimensi: {lebar_lagi.shape[0]} baris x {lebar_lagi.shape[1]} kolom")
if __name__ == "__main__":
main()schema lebar (1 baris per stasiun per cap waktu):
ts station_id suhu_c kelembapan tekanan_hpa
2026-11-01 00:00:00 STA01 24.1 62.0 1013.2
2026-11-01 00:15:00 STA01 24.4 61.5 1013.1
2026-11-01 00:00:00 STA02 22.8 70.2 1012.8
2026-11-01 00:15:00 STA02 23.0 69.8 1012.9
dimensi: 4 baris x 5 kolom
schema sempit (1 baris per pengukuran):
ts station_id metric nilai
2026-11-01 00:00:00 STA01 suhu_c 24.1
2026-11-01 00:15:00 STA01 suhu_c 24.4
2026-11-01 00:00:00 STA02 suhu_c 22.8
2026-11-01 00:15:00 STA02 suhu_c 23.0
2026-11-01 00:00:00 STA01 kelembapan 62.0
2026-11-01 00:15:00 STA01 kelembapan 61.5
2026-11-01 00:00:00 STA02 kelembapan 70.2
2026-11-01 00:15:00 STA02 kelembapan 69.8
2026-11-01 00:00:00 STA01 tekanan_hpa 1013.2
2026-11-01 00:15:00 STA01 tekanan_hpa 1013.1
2026-11-01 00:00:00 STA02 tekanan_hpa 1012.8
2026-11-01 00:15:00 STA02 tekanan_hpa 1012.9
dimensi: 12 baris x 4 kolom
schema lebar hasil konversi ulang:
ts station_id kelembapan suhu_c tekanan_hpa
2026-11-01 00:00:00 STA01 62.0 24.1 1013.2
2026-11-01 00:00:00 STA02 70.2 22.8 1012.8
2026-11-01 00:15:00 STA01 61.5 24.4 1013.1
2026-11-01 00:15:00 STA02 69.8 23.0 1012.9
dimensi: 4 baris x 5 kolomKeluaran di atas memperlihatkan tiga hal. Pertama, schema lebar memuat empat baris dengan lima kolom, sedangkan schema sempit memuat dua belas baris dengan empat kolom. Jumlah baris sempit adalah jumlah baris lebar dikalikan banyaknya metrik. Kedua, konversi ulang menghasilkan dimensi yang sama, yaitu empat baris dan lima kolom, sehingga tidak ada kehilangan informasi pada konversi bolak-balik. Ketiga, urutan kolom pada schema lebar hasil konversi berubah menjadi urutan alfabetis, sebab pivot_table mengurutkan kolom secara default. Perilaku ini wajar pada pandas, tetapi pada basis data produksi urutan kolom ditentukan oleh schema yang didefinisikan saat CREATE TABLE.
Tradeoff yang disampaikan jujur#
Pilihan antara dua schema tidak bebas biaya. Schema sempit menambah jumlah baris sebanyak banyaknya metrik, sehingga indeks pada cap waktu tumbuh lebih cepat, demikian juga ukuran chunk. Sebaliknya, schema lebar memerlukan daftar kolom yang stabil, sehingga menambah metrik baru berarti mengubah schema, yang pada tabel berisi miliaran baris bukanlah operasi murah. Beberapa basis data time-series mengakomodasi perubahan kolom dengan operasi online schema change, tetapi biayanya tetap ada, yaitu penulisan ulang tabel di latar belakang.
Pola query juga menentukan pilihan. Bila sebagian besar query meminta satu metrik pada banyak seri, misalnya “suhu semua stasiun”, schema sempit memerlukan pemindaian dengan filter metric='suhu_c', sedangkan schema lebar membaca satu kolom saja. Bila query meminta banyak metrik untuk satu seri, misalnya “suhu, kelembapan, dan tekanan STA01”, schema lebar membaca satu baris, sedangkan schema sempit membaca tiga. Pemilihan schema sebaiknya mengikuti pola query yang dominan, bukan dugaan tentang masa depan.
Sebagian besar basis data time-series modern mengadopsi pendekatan hibrida. Schema utama disusun lebar untuk metrik yang stabil dan sering dibaca bersamaan, sedangkan metrik yang jarang digunakan atau baru ditambahkan disimpan pada schema sempit terpisah. Pemisahan ini menjaga tabel utama tetap ramping sekaligus memberi ruang untuk pertumbuhan tanpa perubahan schema. Pada PostgreSQL dengan TimescaleDB, pemisahan semacam ini diterapkan dengan dua hypertable berbeda yang berbagi cap waktu dan identitas seri, sehingga query antar-tabel tetap dapat digabung dengan JOIN.
Kesalahan umum#
- Memilih schema lebar karena mirip dengan tabel operasional biasa, lalu menambah kolom setiap kali sensor baru dipasang. Akibatnya tabel memiliki ratusan kolom yang sebagian besar kosong.
- Menggunakan schema sempit tanpa indeks gabungan pada
(ts, station_id, metric). Query rentang waktu menjadi pemindaian penuh, padahal indeks itulah yang membuat schema sempit layak. - Menyimpan satuan sebagai bagian dari nama metrik, misalnya
suhu_cdansuhu_fsebagai dua metrik berbeda. Satuan sebaiknya menjadi metadata tetap, bukan dimensi yang menggandakan jumlah baris.
Ringkasan#
- Schema sempit menyimpan satu pengukuran per baris dan unggul ketika daftar metrik berubah, sedangkan schema lebar menyimpan banyak kolom per baris dan unggul ketika daftar metrik tetap.
- Konversi antara dua bentuk dengan
meltdanpivotbersifat reversibel pada pandas, tetapi pada basis data produksi perubahan schema tidak gratis. - Pemilihan schema sebaiknya mengikuti pola query yang dominan, sebab pemindaian satu kolom berbeda dari pemindaian satu metrik pada banyak baris.
Referensi#
- Design your data model — Timescale — Panduan resmi TimescaleDB untuk merancang model data hypertable, termasuk pertimbangan schema lebar.
- Line protocol — InfluxDB — Sintaks resmi line protocol InfluxDB yang menyiratkan schema sempit satu pengukuran per titik.
- pandas.melt — pandas
— Dokumentasi resmi operasi
meltsebagai padanan schema lebar ke sempit.