[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-partisi-tabel-postgresql-10-juta-baris":3},{"article":4,"author":54},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":24,"related_articles":35},"d2000000-0000-0000-0000-000000000125","a0000000-0000-0000-0000-000000000025","Partisi Tabel PostgreSQL — Ketika Tabel Anda Mencapai 10 Juta+ Baris","partisi-tabel-postgresql-10-juta-baris","Panduan partisi tabel PostgreSQL: kapan mempartisi, jenis partisi (range, list, hash), implementasi migrasi, dan dampak performa pada query dan maintenance.","## Kapan Mempartisi\n\nPartisi tabel adalah teknik membagi satu tabel logis menjadi beberapa tabel fisik yang lebih kecil. PostgreSQL mengelolanya secara transparan — query terhadap tabel utama secara otomatis diarahkan ke partisi yang relevan.\n\nAnda perlu mempertimbangkan partisi ketika:\n- Tabel memiliki lebih dari 10 juta baris\n- Query WHERE selalu menyertakan kolom tertentu (tanggal, locale, tenant)\n- VACUUM memakan waktu terlalu lama\n- Anda perlu menghapus data lama secara efisien\n\n## Jenis Partisi\n\n### 1. Range Partitioning\nPaling umum. Membagi berdasarkan rentang nilai — biasanya tanggal:\n\n```sql\nCREATE TABLE events (\n    id UUID DEFAULT gen_random_uuid(),\n    event_type TEXT NOT NULL,\n    payload JSONB NOT NULL,\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n) PARTITION BY RANGE (created_at);\n\n-- Partisi per bulan\nCREATE TABLE events_2024_01 PARTITION OF events\n    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');\nCREATE TABLE events_2024_02 PARTITION OF events\n    FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');\nCREATE TABLE events_2024_03 PARTITION OF events\n    FOR VALUES FROM ('2024-03-01') TO ('2024-04-01');\n```\n\n### 2. List Partitioning\nMembagi berdasarkan nilai diskrit — cocok untuk multi-tenant atau multi-locale:\n\n```sql\nCREATE TABLE articles (\n    id UUID DEFAULT gen_random_uuid(),\n    title TEXT NOT NULL,\n    content TEXT NOT NULL,\n    locale TEXT NOT NULL,\n    published_at TIMESTAMPTZ\n) PARTITION BY LIST (locale);\n\nCREATE TABLE articles_en PARTITION OF articles FOR VALUES IN ('en');\nCREATE TABLE articles_id PARTITION OF articles FOR VALUES IN ('id');\nCREATE TABLE articles_ru PARTITION OF articles FOR VALUES IN ('ru');\nCREATE TABLE articles_other PARTITION OF articles DEFAULT;\n```\n\n### 3. Hash Partitioning\nMendistribusikan baris secara merata — cocok ketika tidak ada kolom range\u002Flist yang jelas:\n\n```sql\nCREATE TABLE user_sessions (\n    id UUID DEFAULT gen_random_uuid(),\n    user_id UUID NOT NULL,\n    data JSONB,\n    created_at TIMESTAMPTZ DEFAULT NOW()\n) PARTITION BY HASH (user_id);\n\nCREATE TABLE user_sessions_0 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 0);\nCREATE TABLE user_sessions_1 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 1);\nCREATE TABLE user_sessions_2 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 2);\nCREATE TABLE user_sessions_3 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 3);\n```\n\n## Migrasi dari Tabel Non-Partisi\n\n```sql\n-- 1. Rename tabel asli\nALTER TABLE events RENAME TO events_old;\n\n-- 2. Buat tabel partisi baru\nCREATE TABLE events (...) PARTITION BY RANGE (created_at);\n\n-- 3. Buat partisi\nCREATE TABLE events_2024_01 PARTITION OF events ...;\n\n-- 4. Migrasikan data\nINSERT INTO events SELECT * FROM events_old;\n\n-- 5. Verifikasi dan hapus tabel lama\nDROP TABLE events_old;\n```\n\n## Partition Pruning\n\nPartition pruning adalah optimasi di mana PostgreSQL hanya memindai partisi yang relevan:\n\n```sql\n-- Hanya memindai events_2024_01\nEXPLAIN SELECT * FROM events WHERE created_at = '2024-01-15';\n\n-- Output:\n-- Append\n--   -> Seq Scan on events_2024_01\n--        Filter: (created_at = '2024-01-15')\n```\n\nTanpa partisi, query akan memindai seluruh tabel. Dengan partisi, PostgreSQL melewatkan partisi yang tidak relevan.\n\n## Dampak pada Performa\n\n| Operasi | Tanpa Partisi | Dengan Partisi |\n|---------|---------------|----------------|\n| SELECT WHERE date | Full scan 100M rows | Scan 1 partisi (~3M rows) |\n| DELETE data lama | Slow, generates WAL | DROP TABLE, instant |\n| VACUUM | Locks 100M row table | Vacuum per partisi |\n| Index rebuild | Hours | Minutes per partisi |\n\n## Otomatisasi Partisi\n\n```sql\n-- Buat partisi secara otomatis dengan pg_partman\nCREATE EXTENSION pg_partman;\n\nSELECT partman.create_parent(\n    p_parent_table => 'public.events',\n    p_control => 'created_at',\n    p_type => 'native',\n    p_interval => '1 month',\n    p_premake => 3  -- Buat 3 partisi ke depan\n);\n```\n\n## Kesimpulan\n\nPartisi tabel PostgreSQL adalah teknik kritis ketika data tumbuh melewati 10 juta baris. Range partitioning untuk data time-series, list untuk multi-tenant\u002Flocale, dan hash untuk distribusi merata. Partition pruning memastikan query hanya menyentuh data yang relevan, dan maintenance (VACUUM, reindex) menjadi jauh lebih cepat.","\u003Ch2 id=\"kapan-mempartisi\">Kapan Mempartisi\u003C\u002Fh2>\n\u003Cp>Partisi tabel adalah teknik membagi satu tabel logis menjadi beberapa tabel fisik yang lebih kecil. PostgreSQL mengelolanya secara transparan — query terhadap tabel utama secara otomatis diarahkan ke partisi yang relevan.\u003C\u002Fp>\n\u003Cp>Anda perlu mempertimbangkan partisi ketika:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Tabel memiliki lebih dari 10 juta baris\u003C\u002Fli>\n\u003Cli>Query WHERE selalu menyertakan kolom tertentu (tanggal, locale, tenant)\u003C\u002Fli>\n\u003Cli>VACUUM memakan waktu terlalu lama\u003C\u002Fli>\n\u003Cli>Anda perlu menghapus data lama secara efisien\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"jenis-partisi\">Jenis Partisi\u003C\u002Fh2>\n\u003Ch3>1. Range Partitioning\u003C\u002Fh3>\n\u003Cp>Paling umum. Membagi berdasarkan rentang nilai — biasanya tanggal:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE TABLE events (\n    id UUID DEFAULT gen_random_uuid(),\n    event_type TEXT NOT NULL,\n    payload JSONB NOT NULL,\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n) PARTITION BY RANGE (created_at);\n\n-- Partisi per bulan\nCREATE TABLE events_2024_01 PARTITION OF events\n    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');\nCREATE TABLE events_2024_02 PARTITION OF events\n    FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');\nCREATE TABLE events_2024_03 PARTITION OF events\n    FOR VALUES FROM ('2024-03-01') TO ('2024-04-01');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>2. List Partitioning\u003C\u002Fh3>\n\u003Cp>Membagi berdasarkan nilai diskrit — cocok untuk multi-tenant atau multi-locale:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE TABLE articles (\n    id UUID DEFAULT gen_random_uuid(),\n    title TEXT NOT NULL,\n    content TEXT NOT NULL,\n    locale TEXT NOT NULL,\n    published_at TIMESTAMPTZ\n) PARTITION BY LIST (locale);\n\nCREATE TABLE articles_en PARTITION OF articles FOR VALUES IN ('en');\nCREATE TABLE articles_id PARTITION OF articles FOR VALUES IN ('id');\nCREATE TABLE articles_ru PARTITION OF articles FOR VALUES IN ('ru');\nCREATE TABLE articles_other PARTITION OF articles DEFAULT;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>3. Hash Partitioning\u003C\u002Fh3>\n\u003Cp>Mendistribusikan baris secara merata — cocok ketika tidak ada kolom range\u002Flist yang jelas:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE TABLE user_sessions (\n    id UUID DEFAULT gen_random_uuid(),\n    user_id UUID NOT NULL,\n    data JSONB,\n    created_at TIMESTAMPTZ DEFAULT NOW()\n) PARTITION BY HASH (user_id);\n\nCREATE TABLE user_sessions_0 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 0);\nCREATE TABLE user_sessions_1 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 1);\nCREATE TABLE user_sessions_2 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 2);\nCREATE TABLE user_sessions_3 PARTITION OF user_sessions\n    FOR VALUES WITH (MODULUS 4, REMAINDER 3);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"migrasi-dari-tabel-non-partisi\">Migrasi dari Tabel Non-Partisi\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- 1. Rename tabel asli\nALTER TABLE events RENAME TO events_old;\n\n-- 2. Buat tabel partisi baru\nCREATE TABLE events (...) PARTITION BY RANGE (created_at);\n\n-- 3. Buat partisi\nCREATE TABLE events_2024_01 PARTITION OF events ...;\n\n-- 4. Migrasikan data\nINSERT INTO events SELECT * FROM events_old;\n\n-- 5. Verifikasi dan hapus tabel lama\nDROP TABLE events_old;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"partition-pruning\">Partition Pruning\u003C\u002Fh2>\n\u003Cp>Partition pruning adalah optimasi di mana PostgreSQL hanya memindai partisi yang relevan:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- Hanya memindai events_2024_01\nEXPLAIN SELECT * FROM events WHERE created_at = '2024-01-15';\n\n-- Output:\n-- Append\n--   -&gt; Seq Scan on events_2024_01\n--        Filter: (created_at = '2024-01-15')\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Tanpa partisi, query akan memindai seluruh tabel. Dengan partisi, PostgreSQL melewatkan partisi yang tidak relevan.\u003C\u002Fp>\n\u003Ch2 id=\"dampak-pada-performa\">Dampak pada Performa\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Operasi\u003C\u002Fth>\u003Cth>Tanpa Partisi\u003C\u002Fth>\u003Cth>Dengan Partisi\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>SELECT WHERE date\u003C\u002Ftd>\u003Ctd>Full scan 100M rows\u003C\u002Ftd>\u003Ctd>Scan 1 partisi (~3M rows)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>DELETE data lama\u003C\u002Ftd>\u003Ctd>Slow, generates WAL\u003C\u002Ftd>\u003Ctd>DROP TABLE, instant\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>VACUUM\u003C\u002Ftd>\u003Ctd>Locks 100M row table\u003C\u002Ftd>\u003Ctd>Vacuum per partisi\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Index rebuild\u003C\u002Ftd>\u003Ctd>Hours\u003C\u002Ftd>\u003Ctd>Minutes per partisi\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Ch2 id=\"otomatisasi-partisi\">Otomatisasi Partisi\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- Buat partisi secara otomatis dengan pg_partman\nCREATE EXTENSION pg_partman;\n\nSELECT partman.create_parent(\n    p_parent_table =&gt; 'public.events',\n    p_control =&gt; 'created_at',\n    p_type =&gt; 'native',\n    p_interval =&gt; '1 month',\n    p_premake =&gt; 3  -- Buat 3 partisi ke depan\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"kesimpulan\">Kesimpulan\u003C\u002Fh2>\n\u003Cp>Partisi tabel PostgreSQL adalah teknik kritis ketika data tumbuh melewati 10 juta baris. Range partitioning untuk data time-series, list untuk multi-tenant\u002Flocale, dan hash untuk distribusi merata. Partition pruning memastikan query hanya menyentuh data yang relevan, dan maintenance (VACUUM, reindex) menjadi jauh lebih cepat.\u003C\u002Fp>\n","id","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:25.150494Z","Partisi Tabel PostgreSQL — 10 Juta+ Baris","Panduan partisi PostgreSQL: range, list, hash partitioning, migrasi, partition pruning, dan dampak performa.","partisi PostgreSQL",null,"index, follow",[22,27,31],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000012","DevOps","devops","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000022","Performance","performance",{"id":32,"name":33,"slug":34,"created_at":26},"c0000000-0000-0000-0000-000000000005","PostgreSQL","postgresql",[36,42,48],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":24,"published_at":41},"d0000000-0000-0000-0000-000000000644","Platform Engineering Memakan DevOps: Membangun Internal Developer Platform di 2026","platform-engineering-memakan-devops-membangun-idp-2026","80% organisasi engineering besar kini memiliki tim platform khusus, naik dari 45% di 2024. Internal developer platform — portal self-service, infrastruktur yang sudah disetujui, guardrail otomatis — telah menjadi cara standar untuk menghadirkan DevOps secara besar-besaran.","2026-03-28T10:44:47.476351Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":24,"published_at":47},"d0000000-0000-0000-0000-000000000643","Observabilitas Tanpa Instrumentasi: Bagaimana eBPF Menggantikan Armada Sidecar","observabilitas-tanpa-instrumentasi-ebpf-menggantikan-armada-sidecar","67% tim Kubernetes kini menggunakan alat observabilitas berbasis eBPF, naik dari 29% di 2024. Dengan memindahkan pengumpulan telemetri ke kernel, eBPF menghilangkan kontainer sidecar, memangkas penggunaan RAM sebesar 84%, dan memberikan overhead CPU di bawah 1%.","2026-03-28T10:44:47.469045Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":24,"published_at":53},"d0000000-0000-0000-0000-000000000642","WASI 0.3 dan Kematian Cold Start: Wasm Sisi Server di Produksi","wasi-0-3-kematian-cold-start-wasm-sisi-server-di-produksi","WASI 0.3 dirilis pada Februari 2026 dengan async I\u002FO native, tipe stream, dan dukungan socket penuh. WebAssembly sisi server kini menghadirkan cold start dalam hitungan mikrodetik, dan setiap penyedia cloud besar menawarkan Wasm serverless.","2026-03-28T10:44:47.445780Z",{"id":13,"name":55,"slug":56,"bio":57,"photo_url":19,"linkedin":19,"role":58,"created_at":59,"updated_at":59},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]