Optimasi Query SQL: 10 Teknik yang Langsung Kerasa Efeknya
Blog/Tutorial SQL/Optimasi Query SQL: 10 Teknik yang Langsung Kerasa Efeknya

Optimasi Query SQL: 10 Teknik yang Langsung Kerasa Efeknya

BimaBima
·29 Maret 2026·11 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Optimasi query SQL yang paling besar dampaknya biasanya cuma tiga hal: kasih index di kolom yang sering kamu filter, hindari SELECT bintang, dan filter data sebelum JOIN, bukan sesudah. Sebelum ngubah apa pun, jalanin EXPLAIN ANALYZE dulu buat lihat di mana waktunya kebuang. Ngubah query berdasarkan tebakan sering bikin lebih lambat, bukan lebih cepat.

Optimasi query SQL yang paling besar dampaknya biasanya cuma tiga hal: index di kolom yang sering difilter, berhenti pakai SELECT *, dan filter data sebelum JOIN.

Sisanya pelengkap. Tapi pelengkap yang kadang nyelametin kamu waktu tiga teknik pertama udah kepakai dan query-nya masih lambat.

Satu aturan sebelum mulai: jangan ubah apa pun sebelum kamu jalanin EXPLAIN ANALYZE. Ngoptimasi berdasarkan tebakan sering bikin lebih lambat, bukan lebih cepat.

1. Ambil kolom yang kamu butuh aja

SELECT * narik semua kolom, termasuk kolom deskripsi yang panjangnya 2 KB dan gak kamu pakai.

-- Lambat
SELECT * FROM transaksi WHERE tanggal >= '2026-01-01';

-- Cepat
SELECT id, kota, total FROM transaksi WHERE tanggal >= '2026-01-01';

Efeknya dua lapis. Pertama, data yang dibaca dari disk lebih sedikit. Kedua, dan ini yang lebih penting: SELECT * bikin Index Only Scan gak mungkin kepakai. Database terpaksa balik ke tabel buat ngambil kolom yang gak ada di index.

Di tabel transaksi toko_berkah yang punya 14 kolom, ganti dari SELECT * jadi 3 kolom bikin query turun dari 2,1 detik ke 780 ms. Cuma dari ini.

2. Kasih index di kolom yang sering difilter

Ini teknik dengan rasio dampak-per-usaha paling tinggi. Satu baris SQL, efeknya bisa ratusan kali lipat.

CREATE INDEX idx_transaksi_tanggal ON transaksi (tanggal);

Kolom yang layak dikasih index: yang muncul di WHERE, JOIN, atau ORDER BY, dan sering dipakai.

Buat query yang sering nyaring dua kolom sekaligus, bikin composite index:

CREATE INDEX idx_transaksi_kota_tanggal ON transaksi (kota, tanggal);

Urutan kolom di composite index itu penting. Index (kota, tanggal) kepakai buat filter kota doang, dan buat filter kota + tanggal. Tapi gak kepakai buat filter tanggal doang.

Aturannya: kolom yang paling sering difilter, taruh di depan.

3. Jangan bungkus kolom dengan fungsi di WHERE

Ini pembunuh index yang paling senyap.

-- Index mati
SELECT id, total FROM transaksi WHERE YEAR(tanggal) = 2026;

-- Index hidup
SELECT id, total FROM transaksi 
WHERE tanggal >= '2026-01-01' AND tanggal < '2027-01-01';

Kenapa? Index nyimpen nilai tanggal, bukan nilai YEAR(tanggal). Begitu kamu bungkus kolomnya dengan fungsi, database gak bisa lagi nyari lewat index — dia harus hitung fungsi itu di tiap baris.

Sama juga buat teks:

-- Index mati
WHERE UPPER(kota) = 'JAKARTA'

-- Index hidup
WHERE kota = 'Jakarta'

Kalau kamu emang butuh pencarian tanpa peduli huruf besar-kecil, bikin index-nya di ekspresi itu:

CREATE INDEX idx_kota_upper ON transaksi (UPPER(kota));

4. Filter dulu, JOIN belakangan

Kalau kamu JOIN dua tabel besar lalu baru filter, database sering ngerjain gabungan yang jauh lebih besar dari yang kamu butuh.

WITH transaksi_2026 AS (
    SELECT produk_id, kota, total
    FROM transaksi
    WHERE tanggal >= '2026-01-01'
)
SELECT p.kategori, t.kota, SUM(t.total) AS omzet
FROM transaksi_2026 t
JOIN produk p ON p.id = t.produk_id
GROUP BY p.kategori, t.kota;

Query planner yang bagus sering udah ngelakuin ini sendiri. Tapi "sering" bukan "selalu" — apalagi kalau statistik tabelnya basi.

Nulis eksplisit kayak gini juga bikin query kamu lebih gampang dibaca orang lain. Itu bonus yang gak keitung di benchmark.

5. Ganti correlated subquery dengan window function

Correlated subquery itu subquery yang jalan sekali per baris hasil. Kalau hasilnya 100 ribu baris, subquery itu jalan 100 ribu kali.

-- Lambat: subquery jalan tiap baris
SELECT 
    kota,
    total,
    (SELECT AVG(total) FROM transaksi t2 WHERE t2.kota = t1.kota) AS rata_kota
FROM transaksi t1
WHERE tanggal >= '2026-01-01';

-- Cepat: sekali baca, semua dihitung
SELECT
    kota,
    total,
    AVG(total) OVER (PARTITION BY kota) AS rata_kota
FROM transaksi
WHERE tanggal >= '2026-01-01';

Di data toko_berkah dengan 2,4 juta baris, versi pertama makan 38 detik. Versi window function: 1,2 detik.

Kalau kamu belum familiar sama window function, mulai dari glosarium window function.

6. EXISTS lebih cepat dari IN buat subquery besar

-- Lambat kalau subquery-nya ngembaliin jutaan baris
SELECT id, nama FROM produk
WHERE id IN (SELECT produk_id FROM transaksi);

-- Cepat: berhenti begitu ketemu satu
SELECT p.id, p.nama
FROM produk p
WHERE EXISTS (
    SELECT 1 FROM transaksi t WHERE t.produk_id = p.id
);

EXISTS berhenti nyari begitu nemu satu baris yang cocok. IN sering ngumpulin dulu semua hasil subquery-nya.

Bonus: kalau kolom di subquery bisa berisi NULL, NOT IN bakal ngasih hasil kosong yang bikin kamu bingung berjam-jam. NOT EXISTS gak punya masalah itu.

7. Pakai LIMIT waktu eksplorasi

Waktu kamu lagi ngintip data buat pertama kali, kamu gak butuh 2 juta baris.

SELECT id, kota, total FROM transaksi LIMIT 100;

Kedengeran sepele, tapi ini nyelametin kamu dari nge-hang bikin editor SQL kamu — dan nyelametin database production dari beban yang gak perlu.

Hati-hati satu hal: LIMIT tanpa ORDER BY gak ngasih jaminan baris mana yang keluar. Buat eksplorasi, gak masalah. Buat laporan, selalu pasangin sama ORDER BY.

8. Kurangi data yang di-sort

Sorting itu mahal. Kalau data yang di-sort gak muat di memori, database numpahin ke disk — dan itu lambat banget.

Tandanya kelihatan di query plan:

Sort Method: external merge  Disk: 84200kB

Kata Disk di situ artinya sorting kamu tumpah. Dua cara benerinnya:

  • Filter dulu sebelum ORDER BY, biar data yang di-sort lebih sedikit.
  • Bikin index di kolom ORDER BY, biar database bisa baca data yang udah terurut dan skip sorting-nya sama sekali.

9. Hindari SELECT DISTINCT sebagai penambal

Banyak orang nambahin DISTINCT waktu hasil query-nya ada duplikat. Padahal duplikat itu biasanya gejala dari JOIN yang salah.

-- Nambal gejala
SELECT DISTINCT p.nama FROM produk p
JOIN transaksi t ON t.produk_id = p.id;

-- Benerin akarnya
SELECT p.nama FROM produk p
WHERE EXISTS (SELECT 1 FROM transaksi t WHERE t.produk_id = p.id);

DISTINCT maksa database ngurutin atau bikin hash dari seluruh hasil buat buang duplikat. Itu kerjaan mahal yang sebenernya bisa dihindari.

Kalau kamu nemu DISTINCT di query kamu, tanya dulu: kenapa ada duplikat? Biasanya jawabannya ada di JOIN yang kena baris ganda.

10. Pakai materialized view buat query yang berulang

Query yang sama dijalanin 200 orang tiap pagi, hasilnya gak harus real-time, dan hitungnya mahal? Simpan hasilnya.

CREATE MATERIALIZED VIEW omzet_bulanan AS
SELECT 
    DATE_TRUNC('month', tanggal) AS bulan,
    kota,
    SUM(total) AS omzet
FROM transaksi
GROUP BY 1, 2;

Lalu refresh sekali sehari:

REFRESH MATERIALIZED VIEW omzet_bulanan;

200 orang itu sekarang baca hasil yang udah jadi. Query yang tadinya 12 detik jadi 30 ms.

Jangan pakai ini buat data yang harus akurat detik itu juga — stok barang, saldo, atau apa pun yang orang bakal ambil keputusan langsung dari situ.

Contoh kasus: dari 40 detik jadi 200 milidetik

Ini query laporan bulanan toko_berkah yang aslinya begini:

SELECT *
FROM transaksi t
JOIN produk p ON p.id = t.produk_id
JOIN kategori k ON k.id = p.kategori_id
WHERE YEAR(t.tanggal) = 2026
  AND UPPER(t.kota) = 'JAKARTA'
ORDER BY t.total DESC;

Waktu eksekusi: 41,3 detik di tabel 2,4 juta baris.

EXPLAIN ANALYZE nunjukin Seq Scan di transaksi, dengan 2,3 juta baris dibuang oleh filter.

Perbaikannya, satu per satu:

  1. Ganti SELECT * jadi 5 kolom yang beneran dipakai. → 28,7 detik
  2. Ganti YEAR(tanggal) jadi range tanggal. → 26,1 detik (belum ada index, jadi belum kerasa)
  3. Ganti UPPER(kota) jadi kota = 'Jakarta'. → 25,8 detik
  4. Bikin composite index (kota, tanggal). → 0,89 detik
  5. Bikin index di produk_id buat JOIN-nya. → 0,21 detik

Total: dari 41,3 detik jadi 210 ms. 197 kali lebih cepat.

Perhatiin langkah 4. Itu yang paling besar dampaknya — turun dari 25,8 detik ke 0,89 detik dalam satu langkah.

Tapi index itu cuma kepakai karena langkah 2 dan 3 udah ngelepas fungsi dari kolom WHERE. Kalau YEAR(tanggal) masih ada, index-nya gak bakal kesentuh sama sekali.

Itu poinnya. Teknik-teknik ini saling numpuk.

Kesalahan umum waktu optimasi

1. Ngubah beberapa hal sekaligus

Kamu ubah 4 hal, query jadi cepat, tapi kamu gak tau yang mana yang berhasil. Ubah satu, ukur, ubah lagi. Lebih lama sedikit, tapi kamu jadi ngerti.

2. Bikin index buat semua kolom

Index bikin SELECT cepat, tapi INSERT dan UPDATE lambat — tiap tulis data, semua index-nya ikut diperbarui. Di tabel yang sering ditulis, kebanyakan index bisa lebih merugikan dari yang kamu kira.

3. Ngetes di database kecil

Query plan di tabel 1.000 baris beda total sama di 2 juta baris. Database bakal pilih Seq Scan di tabel kecil dan kamu gak lihat masalahnya sama sekali.

4. Lupa jalanin ANALYZE

Habis import jutaan baris, statistik tabel kamu masih ngira tabelnya kecil. Query planner bakal salah pilih rencana.

ANALYZE transaksi;

5. Percaya angka pertama

Query kedua sering lebih cepat dari yang pertama gara-gara data udah masuk cache. Jalanin 3 kali, ambil yang tengah.

Urutan yang aku pakai

  1. Jalanin EXPLAIN ANALYZE. Cari langkah dengan actual time paling besar.
  2. Ada Seq Scan di tabel besar dengan Rows Removed by Filter yang gede? Kolom itu butuh index.
  3. Ada fungsi yang mbungkus kolom di WHERE? Lepas dulu, baru index-nya kepakai.
  4. Ganti SELECT * jadi kolom yang beneran dipakai.
  5. Ada correlated subquery? Ganti pakai JOIN atau window function.
  6. Ukur lagi. Ulangi dari langkah 1.

Referensi lengkap soal cara kerja query planner ada di dokumentasi resmi PostgreSQL.

FAQ

Kenapa query aku lambat padahal datanya gak banyak?

Biasanya ada fungsi di kolom WHERE yang matiin index, atau ada correlated subquery yang jalan berulang tiap baris. Jalanin EXPLAIN ANALYZE dan cari langkah paling lama.

SELECT * beneran bikin lambat?

Iya. Selain narik kolom yang gak kepakai, dia bikin Index Only Scan gak mungkin dipakai.

Berapa banyak index yang boleh dibikin?

Cuma di kolom yang sering muncul di WHERE, JOIN, atau ORDER BY. Tiap index bikin tulis data jadi lebih lambat.

Lebih cepat mana, JOIN atau subquery?

Mirip, kecuali correlated subquery — itu yang beneran lambat. Ganti pakai JOIN atau window function.

Kapan pakai materialized view?

Waktu query yang sama dipakai berulang, mahal, dan hasilnya gak harus real-time.

Penutup

Tiga hal yang paling sering nyelesaiin masalah:

  • Index di kolom yang sering difilter — dampaknya paling besar per usaha.
  • Lepas fungsi dari kolom di WHERE — kalau gak, index kamu gak kepakai.
  • EXPLAIN ANALYZE sebelum ngubah apa pun — biar kamu gak ngoptimasi bagian yang salah.

Ambil query paling lambat di kerjaan kamu minggu ini. Jalanin EXPLAIN ANALYZE, cari Seq Scan-nya, dan bikin satu index. Sepuluh menit, dan kemungkinan besar query itu jadi puluhan kali lebih cepat.

Mau latihan nulis query dan langsung lihat waktu eksekusinya? Coba NgulikSQL — gratis, langsung di browser, gak perlu install database.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel Terkait

7 SQL Client Gratis Terbaik buat Analis Data (2026)
Tutorial SQL
10 Juli 2026•9 menit baca

7 SQL Client Gratis Terbaik buat Analis Data (2026)

Nggak perlu bayar buat nulis query. Ini 7 SQL client gratis yang beneran dipakai analis, plus kelebihan dan kekurangannya masing-masing.

BimaBima
SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim
Tutorial SQL
7 Juli 2026•9 menit baca

SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim

Sepuluh aturan SQL style guide yang bikin query kamu kebaca sama tim — dan sama kamu sendiri 6 bulan lagi. Lengkap dengan contoh sebelum-sesudah.

BimaBima
Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya
Tutorial SQL
4 Juli 2026•11 menit baca

Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya

Contoh soal take-home test SQL yang beneran dipakai perusahaan, dikerjain step by step — dari baca soal, nulis query, sampai nyusun insight yang bikin recruiter nengok.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

Copyright © 2026 - All rights reserved

LINKS
SupportPricingDatasetBlogAffiliates
LEGAL
Terms of servicesPrivacy policy
Ngulik Data
DatasetLeaderboardBlogStore