EXISTS vs IN di SQL: Perbedaan dan Performa (2026)
Blog/Tutorial SQL/EXISTS vs IN di SQL: Perbedaan dan Performa (2026)

EXISTS vs IN di SQL: Perbedaan dan Performa (2026)

BimaBima
·11 November 2026·9 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

EXISTS dan IN sama-sama dipakai buat nyaring baris berdasarkan hasil subquery, tapi cara kerjanya beda. IN ngumpulin semua nilai subquery lalu ngecek kecocokan, sedangkan EXISTS berhenti begitu nemu satu baris yang cocok. EXISTS biasanya lebih cepat buat subquery besar dan aman dari jebakan NULL, sedangkan IN lebih ringkas buat daftar nilai yang kecil dan tetap.

EXISTS dan IN sama-sama dipakai buat nyaring baris berdasarkan hasil dari subquery. Bedanya ada di cara mereka ngecek kecocokan, dan itu ngaruh ke performa dan hasil pas ada nilai NULL.

Salah pilih di antara keduanya bisa bikin query kamu lambat di tabel besar, atau lebih parah, ngasih hasil yang salah tanpa error apa pun. Dua-duanya kelihatan mirip, jadi banyak orang pakai asal jadi.

Di sini aku jelasin beda cara kerjanya, mana yang lebih cepat, dan jebakan NULL yang sering bikin bug diam-diam.

Apa beda EXISTS dan IN di SQL?

IN ngumpulin semua nilai dari subquery jadi satu daftar, lalu ngecek apakah nilai baris ada di daftar itu. EXISTS jalanin subquery buat tiap baris dan berhenti begitu nemu satu kecocokan, balikin true atau false. IN peduli sama nilainya, EXISTS cuma peduli apakah ada baris yang cocok.

Contoh IN, nyari pelanggan yang pernah transaksi:

SELECT nama
FROM pelanggan
WHERE id IN (SELECT pelanggan_id FROM transaksi);

Contoh EXISTS buat pertanyaan yang sama:

SELECT nama
FROM pelanggan p
WHERE EXISTS (
    SELECT 1 FROM transaksi t
    WHERE t.pelanggan_id = p.id
);

Perhatiin EXISTS pakai SELECT 1. Angka ini nggak penting, karena EXISTS cuma ngecek ada atau nggaknya baris, bukan isinya. Subquery-nya juga nyambung ke tabel luar lewat t.pelanggan_id = p.id, ini disebut correlated subquery.

EXISTS atau IN, mana yang lebih cepat?

Jawabannya tergantung ukuran subquery dan database yang kamu pakai. Tapi ada pola umum yang bisa jadi pegangan. EXISTS biasanya lebih cepat kalau subquery-nya balikin banyak baris, karena dia berhenti di kecocokan pertama tanpa nunggu seluruh daftar kekumpul.

IN sering lebih efisien kalau subquery-nya balikin sedikit nilai yang tetap, atau kalau kamu nulis daftar manual kayak WHERE kota IN ('Jakarta', 'Bandung'). Di kasus ini nggak ada subquery yang mahal buat dijalanin.

SituasiPilihan lebih baik
Subquery balikin ribuan barisEXISTS
Daftar nilai kecil dan tetapIN
Subquery bisa berisi NULLEXISTS
Cek keberadaan baris terkaitEXISTS
Filter kolom sama satu daftar literalIN

Catatan penting: database modern kayak PostgreSQL punya query optimizer yang sering nulis ulang IN jadi bentuk yang mirip EXISTS di belakang layar. Jadi buat kasus sederhana, selisih performanya bisa kecil. Bedanya baru kerasa di tabel besar dengan jutaan baris.

Kenapa IN bisa ngasih hasil salah waktu ada NULL?

Ini jebakan paling bahaya dari IN. Kalau subquery IN balikin nilai NULL di antara hasilnya, kondisi NOT IN bisa nggak ngembaliin baris apa pun, padahal kamu ngarep ada hasil. Ini terjadi tanpa error, jadi gampang kelewat.

Contoh yang bermasalah, nyari pelanggan yang belum pernah transaksi:

-- BAHAYA kalau pelanggan_id ada yang NULL
SELECT nama
FROM pelanggan
WHERE id NOT IN (SELECT pelanggan_id FROM transaksi);

Kalau kolom pelanggan_id ada satu aja yang NULL, query ini balikin nol baris. Penyebabnya cara SQL ngebandingin nilai sama NULL: hasilnya bukan true atau false, tapi "unknown", dan NOT IN nolak semua baris yang statusnya unknown.

NOT EXISTS aman dari masalah ini:

-- AMAN dari jebakan NULL
SELECT nama
FROM pelanggan p
WHERE NOT EXISTS (
    SELECT 1 FROM transaksi t
    WHERE t.pelanggan_id = p.id
);

Aturan praktis yang aku pegang: buat NOT IN, selalu pastikan subquery-nya nggak mungkin balikin NULL, atau ganti aja pakai NOT EXISTS. Buat ngerti konsep terkait, cek juga semi join dan anti join di SQL.

Contoh Kasus: Pelanggan Aktif toko_berkah

Anggap toko_berkah punya tabel pelanggan berisi 8.000 baris dan tabel transaksi berisi 120.000 baris. Kamu mau tau pelanggan mana yang pernah belanja minimal sekali.

-- Versi EXISTS
SELECT p.nama, p.kota
FROM pelanggan p
WHERE EXISTS (
    SELECT 1 FROM transaksi t
    WHERE t.pelanggan_id = p.id
);

Di dataset uji seukuran ini, versi EXISTS umumnya lebih ngebut karena begitu satu transaksi ketemu buat seorang pelanggan, subquery langsung berhenti dan lanjut ke pelanggan berikutnya. Dia nggak perlu ngitung semua 120.000 transaksi.

Kalau kamu pakai IN buat pertanyaan yang sama, database harus ngumpulin daftar semua pelanggan_id dari 120.000 transaksi dulu. Buat daftar sebesar ini, ngumpulin dan ngeceknya makan lebih banyak kerja. Selisihnya kecil di data mini, tapi kerasa di tabel ratusan ribu baris ke atas.

Buat cek kebalikannya, pelanggan yang belum pernah belanja, pakai NOT EXISTS biar aman dari NULL seperti dijelasin tadi.

Kapan sebaiknya pakai IN?

IN tetap pilihan yang bagus dan lebih gampang dibaca di beberapa situasi:

  • Daftar nilai literal. WHERE kota IN ('Jakarta', 'Bandung', 'Surabaya') jauh lebih ringkas daripada nulis EXISTS.
  • Subquery kecil. Kalau subquery cuma balikin belasan nilai, IN gampang dibaca dan performanya nggak masalah.
  • Nggak ada risiko NULL. Buat kondisi IN biasa (bukan NOT IN), NULL nggak sebahaya di NOT IN, jadi lebih aman dipakai.

Buat pemula, saran aku: pakai IN buat daftar pendek yang jelas, pakai EXISTS buat cek keberadaan di tabel besar dan buat semua kasus NOT. Aturan ini nutup mayoritas kebutuhan sehari-hari tanpa harus mikir panjang.

Kesalahan Umum

  • Pakai NOT IN di kolom yang bisa NULL. Ini penyebab bug diam paling sering. Ganti pakai NOT EXISTS atau tambahin WHERE kolom IS NOT NULL di subquery.
  • Nulis SELECT * di dalam EXISTS. Nggak salah, tapi nggak perlu. Pakai SELECT 1 biar niatnya jelas: cuma cek ada atau nggak.
  • Lupa correlated condition di EXISTS. Kalau subquery EXISTS nggak nyambung ke tabel luar, dia bakal selalu true selama ada baris. Pastikan ada kondisi yang ngehubungin kayak t.pelanggan_id = p.id.

FAQ

EXISTS selalu lebih cepat dari IN?

Nggak selalu. EXISTS unggul kalau subquery balikin banyak baris, karena berhenti di kecocokan pertama. Tapi buat daftar nilai kecil atau literal, IN sama cepat atau bahkan lebih ringkas. Database modern juga sering nulis ulang IN jadi bentuk mirip EXISTS otomatis, jadi selisihnya kecil di kasus sederhana. Yang lebih nentuin performa biasanya index dan ukuran data, bukan cuma pilihan EXISTS atau IN.

Apa beda NOT IN dan NOT EXISTS?

Keduanya nyari baris yang nggak punya kecocokan, tapi beda perilaku pas ada NULL. NOT IN bisa balikin nol baris kalau subquery-nya berisi satu saja nilai NULL, karena SQL ngitung perbandingan sama NULL sebagai unknown. NOT EXISTS nggak kena masalah ini dan tetap ngasih hasil bener. Buat kasus NOT, NOT EXISTS umumnya pilihan yang lebih aman kecuali kamu yakin subquery bebas NULL.

Apa itu correlated subquery di EXISTS?

Correlated subquery adalah subquery yang nyambung ke tabel luar lewat kolom bersama, misalnya t.pelanggan_id = p.id. Subquery ini dijalanin sekali buat tiap baris tabel luar, dan hasilnya tergantung baris yang lagi diproses. EXISTS hampir selalu pakai bentuk ini. Bedanya sama subquery biasa yang jalan sekali dan hasilnya sama buat semua baris.

Kenapa EXISTS pakai SELECT 1, bukan SELECT nama kolom?

Karena EXISTS cuma ngecek ada atau nggaknya baris, bukan isinya. Angka 1 di SELECT 1 nggak dipakai buat apa pun, dia cuma placeholder. Kamu bisa nulis SELECT apa saja di situ dan hasilnya sama. Konvensi pakai SELECT 1 bikin niat query jelas: kita cuma peduli keberadaan baris, bukan nilai kolomnya. Ini juga ngasih sinyal ke pembaca kode soal maksud kamu.

Bisa ganti EXISTS pakai JOIN?

Sering bisa, dan kadang JOIN lebih cepat. INNER JOIN bisa gantiin EXISTS buat nyari baris yang punya kecocokan. Tapi hati-hati, JOIN bisa gandain baris kalau tabel kedua punya banyak kecocokan per baris, sedangkan EXISTS selalu ngasih satu baris per baris asal. Kalau kamu cuma butuh cek keberadaan tanpa ngambil kolom dari tabel kedua, EXISTS lebih aman dari duplikat.

Penutup

Ringkasnya: pakai EXISTS buat cek keberadaan di tabel besar dan semua kasus NOT, pakai IN buat daftar nilai kecil yang jelas. EXISTS berhenti di kecocokan pertama, IN ngumpulin semua nilai dulu.

Yang paling perlu kamu inget: NOT IN plus NULL sama dengan bug diam. Kalau ragu subquery-mu bisa berisi NULL, pilih NOT EXISTS.

Mau dalami konsep terkait? Lanjut ke semi join dan anti join di SQL. Detail teknis resmi ada di dokumentasi PostgreSQL.

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

Semi Join dan Anti Join di SQL: Filter Pakai Tabel Lain
Tutorial SQL
14 November 2026•8 menit baca

Semi Join dan Anti Join di SQL: Filter Pakai Tabel Lain

Semi join ngambil baris yang punya pasangan di tabel lain, anti join ngambil yang nggak punya. Keduanya filter, bukan gabung kolom. Ini cara nulisnya di SQL pakai EXISTS dan NOT EXISTS.

BimaBima
Crosstab (Pivot) di PostgreSQL: Ubah Baris Jadi Kolom
Tutorial SQL
2 November 2026•11 menit baca

Crosstab (Pivot) di PostgreSQL: Ubah Baris Jadi Kolom

Crosstab di PostgreSQL mivot data dari format panjang (baris) jadi format lebar (kolom), mirip pivot table Excel. Butuh extension tablefunc, dan ada alternatif pakai CASE atau FILTER kalau kolomnya tetap.

BimaBima
INSERT ON CONFLICT di PostgreSQL
Tutorial SQL
25 Oktober 2026•11 menit baca

INSERT ON CONFLICT di PostgreSQL

INSERT ON CONFLICT bikin PostgreSQL insert baris baru atau update yang udah ada dalam satu perintah, tanpa error gara-gara duplikat primary key.

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.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore