Laravel merilis versi 13.26 dengan dua fitur menarik. Pertama, Read-Through Disks yang memungkinkan filesystem disk melakukan lazy loading dan caching otomatis — cocok untuk migrasi storage gradual. Kedua, debounced event listeners yang memungkinkan event listener hanya dijalankan setelah jeda waktu tertentu, berguna untuk event yang sering trigger tapi cukup diproses sekali.
2. Lerd: Alternatif Open Source Herd untuk Linux & macOS
Lerd adalah tool baru gratis dan open source yang menawarkan pengalaman serupa Herd (environment PHP dari Laravel) tapi bisa jalan di Linux maupun macOS. Bagi developer PHP yang belum mau pakai Herd atau butuh alternatif cross-platform, Lerd layak dicoba.
PHP.net mengumumkan rilis PHP 8.6.0 Beta 1. Ini menandakan PHP 8.6 sudah masuk fase stabilisasi dan siap untuk diuji oleh komunitas. Developer yang ingin mencoba fitur-fitur baru di PHP versi mendatang bisa mulai install sekarang untuk kompatibilitas codebase.
Go 1.27 dirilis dengan berbagai peningkatan performa dan fitur baru. Rilis Go terbaru ini selalu membawa perubahan yang berdampak pada ekosistem backend dan cloud-native development. Worth dicek kalau kamu pakai Go untuk service atau CLI tools.
5. Unsloth Dynamic 3.0: GGUF Lebih Cepat untuk Inference AI
Unsloth merilis Dynamic 3.0 GGUFs — format kuantisasi model AI yang lebih cepat dan efisien untuk inference lokal. Ini penting untuk developer yang menjalankan model LLM di perangkat sendiri atau di server dengan sumber daya terbatas. Optimasi di level GGUF bisa bikin perbedaan besar di kecepatan inference.
OpenRouter, platform populer untuk akses berbagai model AI dari berbagai provider, diakuisisi oleh Stripe. Ini menarik karena menggabungkan infrastruktur pembayaran global Stripe dengan ekosistem model AI yang luas. Bisa jadi sinyal integrasi AI dan payment makin erat di masa depan.
7. Real-Time Data di React: Ring Buffers & OffscreenCanvas
Artikel dari freeCodeCamp membahas teknik untuk menangani data real-time berfrekuensi tinggi di React, menggunakan Ring Buffers untuk manajemen memori efisien dan OffscreenCanvas untuk rendering di luar main thread. Penting untuk dashboard monitoring, visualisasi data, atau aplikasi yang butuh render cepat.
Minggu yang produktif untuk dunia developer. Laravel makin solid dengan 13.26, PHP 8.6 sudah di beta, dan tools AI open source terus berkembang. Selamat coding!
Hari ini saya belajar tentang perbedaan mendasar antara USB-C dan USB4 — dua istilah yang sering dipakai bergantian tapi sebenarnya merujuk pada hal yang sangat berbeda. USB-C adalah nama konektor fisik, sedangkan USB4 adalah protokol yang menentukan seberapa cepat data bergerak, seberapa besar daya yang bisa dialirkan, dan apakah video bisa dikirim lewat kabel yang sama. Artikel ini dibuat berdasarkan liputan dari Gadgets Now (Agustus 2026).
Apa Itu USB-C?
USB-C adalah spesifikasi konektor 24-pin yang didefinisikan oleh USB Implementers Forum (USB-IF). Bentuknya oval dan reversible — bisa dicolok dari arah mana saja. Satu konektor ini membawa daya, data, dan sinyal video sekaligus.
Penting untuk dipahami: konektor USB-C sendiri tidak menentukan kecepatan. Sebuah port USB-C di hp budget mungkin hanya mendukung USB 2.0 (480 Mbps), sementara port USB-C di laptop profesional bisa mendukung USB4 (40 Gbps) atau Thunderbolt 4 (40 Gbps). Bentuk fisiknya sama persis — kemampuannya ditentukan oleh protokol yang di-wiring oleh pabrikan di belakang port.
Untuk pengiriman daya, USB Power Delivery (USB PD) 3.1 berjalan melalui USB-C dengan standar terpisah yang bisa mengatur level daya antar perangkat. Profil Extended Power Range pada USB PD 3.1 bisa mengantarkan daya hingga 240W (48V, 5A) — cukup untuk mengisi daya laptop gaming dan monitor besar. Kabel USB-C yang dirating 60W punya konstruksi internal yang berbeda dari yang dirating 240W, meski konektornya identik.
Sebelumnya saya sudah belajar tentang single index dan composite index di MySQL. Tapi pertanyaan selanjutnya: bagaimana cara memastikan index yang sudah dibuat benar-benar dipakai oleh MySQL? Jawabannya ada di perintah EXPLAIN. Hari ini saya mencatat bagaimana membaca hasil EXPLAIN dan menghubungkannya dengan pemahaman tentang index.
EXPLAIN: Jendela ke Otak MySQL
EXPLAIN adalah perintah di MySQL yang menampilkan execution plan — rencana eksekusi yang akan dilakukan MySQL untuk menjalankan sebuah query. Dengan EXPLAIN, kita bisa melihat apakah index sudah terpakai, berapa banyak baris yang harus diperiksa, dan apakah ada bottleneck tersembunyi.
Cara pakainya sangat sederhana — tinggal tambahkan EXPLAIN di depan query:
-- Tambah EXPLAIN di depan SELECT
EXPLAIN SELECT * FROM users WHERE email = 'rudy@example.com';
-- Bisa juga untuk query kompleks
EXPLAIN SELECT u.nama, COUNT(o.id) AS total_order
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.status = 'active'
GROUP BY u.id;
Setiap Kolom di EXPLAIN: Apa Artinya?
Hasil EXPLAIN berupa tabel dengan beberapa kolom. Berikut penjelasan masing-masing kolom yang paling penting untuk dipahami:
1. id — Nomor Urut Query
Setiap SELECT dalam query diberi nomor id. Jika dua baris punya id yang sama, mereka dieksekusi bersama (misalnya saat JOIN). Jika id berbeda, mereka dieksekusi secara terpisah — misalnya subquery yang dijalankan untuk setiap baris dari outer query.
2. select_type — Jenis SELECT
select_type
Arti
Kapan Muncul
SIMPLE
Query tanpa subquery/UNION
SELECT * FROM t WHERE x=1
PRIMARY
SELECT terluar
Outer query dari subquery/UNION
SUBQUERY
Subquery independent
Dijalankan sekali saja
DEPENDENT SUBQUERY
Subquery bergantung outer query
⚠️ Dijalankan ulang N× per baris outer
MATERIALIZED
Subquery di-materialize ke tabel sementara
Hasilnya di-cache, lalu di-lookup
DERIVED
Subquery di FROM clause
MySQL buat tabel sementara
Yang paling perlu diwaspadai adalah DEPENDENT SUBQUERY — ini artinya subquery dijalankan ulang untuk setiap baris dari tabel induk. Semakin banyak data, semakin lambat.
3. table — Tabel yang Diakses
Nama tabel atau alias yang sedang diakses. Jika tertulis <subqueryN>, berarti itu hasil materialized dari subquery nomor N.
4. type — Cara MySQL Mengambil Baris ⭐
Ini adalah kolom paling penting di EXPLAIN. Kolom type menunjukkan cara MySQL mengambil data dari tabel. Semuanya diurutkan dari yang paling cepat ke yang paling lambat:
type
Arti
Kecepatan
system
Tabel hanya punya 1 baris
⚡ Instan
const
Primary/unique key, hasil 1 baris
⚡ Instan
eq_ref
JOIN pakai primary/unique, 1 baris per kombinasi
⚡⚡ Sangat cepat
ref
Pakai index biasa, bisa lebih dari 1 baris
⚡⚡ Cepat
range
Range scan (BETWEEN, >, <, IN)
✅ Bagus
index
Full index scan (bukan full table)
⚠️ Lambat
ALL
Full table scan — tanpa index
🐌 Terburuk
Rumus cepat: kalau type adalah ALL atau index di tabel yang besar (ribuan baris ke atas), itu tanda ada masalah yang perlu diperbaiki.
5. possible_keys vs key — Index Kandidat vs Index Terpakai
possible_keys menunjukkan index yang bisa dipakai MySQL, sedangkan key menunjukkan index yang benar-benar dipakai. Jika key bernilai NULL, berarti MySQL memilih full table scan karena dianggap lebih cepat.
Ini kembali ke pembahasan single index vs composite index — tidak semua index yang tersedia akan dipakai. MySQL memilih index yang paling efisien berdasarkan selectivitas (seberapa banyak baris yang bisa di-filter).
6. key_len — Panjang Byte Index yang Dipakai
Menunjukkan berapa byte dari index yang benar-benar digunakan. Ini berguna untuk memahami apakah composite index terpakai penuh atau hanya sebagian. Contoh:
Jika key_len kecil padahal composite index-nya punya banyak kolom, berarti hanya sebagian kolom index yang aktif — bisa jadi karena ada gap di leftmost prefix (kembali lagi ke aturan composite index sebelumnya).
7. ref — Apa yang Dibandingkan dengan Index
Nilai ref
Arti
const
Dibandingkan dengan nilai konstan (WHERE x = 5)
func
Dibandingkan dengan hasil fungsi (WHERE YEAR(tgl) = 2025)
table.column
Dibandingkan dengan kolom dari tabel lain (saat JOIN)
NULL
Tidak ada referensi
8. rows — Estimasi Jumlah Baris yang Diperiksa ⭐
Kolom kedua paling penting setelah type. Menunjukkan berapa baris yang estimasi harus diperiksa MySQL. Semakin kecil, semakin cepat. Jika angkanya mendekati total baris di tabel, berarti filter tidak selektif atau index tidak efektif.
Catatan: angka ini adalah estimasi optimizer, bukan jumlah aktual. Untuk memastikan statistik akurat, jalankan:
ANALYZE TABLE nama_tabel;
9. Extra — Info Tambahan
Extra
Arti
Penilaian
Using where
Filter dilakukan setelah MySQL ambil data
Normal
Using index
Covering index — tidak perlu akses tabel utama
✅ Bagus
Using temporary
Pakai tabel sementara (GROUP BY, DISTINCT)
⚠️ Hati-hati
Using filesort
Sorting tidak pakai index
⚠️ Lambat kalau data banyak
Using intersect()
MySQL menggabungkan 2 index (index merge)
⚠️ Pertimbangkan composite index
Using index condition
Index Condition Pushdown — filter di engine storage
✅ Bagus
Yang perlu diwaspadai: Using temporary + Using filesort bersamaan — ini menunjukkan query yang cukup mahal karena MySQL harus membuat tabel sementara DAN mengurutkannya tanpa bantuan index.
Red Flags: Tanda-tanda Query Bermasalah
Setelah memahami setiap kolom, berikut ringkasan tanda-tanda yang harus diwaspadai saat membaca hasil EXPLAIN:
type: ALL di tabel lebih dari 1.000 baris → full table scan, index tidak terpakai
select_type: DEPENDENT SUBQUERY → subquery dijalankan ulang N× per baris outer query
key: NULL padahal possible_keys ada → MySQL menolak index karena dianggap tidak efisien
rows mendekati total baris tabel → filter tidak selektif
Extra: Using intersect() → MySQL harus menggabungkan 2 index (index merge), lebih baik pakai composite index tunggal
Studi Kasus: Dari EXPLAIN ke Perbaikan
Mari kita lihat contoh nyata. Misalnya ada query survei yang hasil EXPLAIN-nya menunjukkan masalah:
EXPLAIN SELECT
s.nama,
(SELECT COUNT(*)
FROM v2_survei_pertanyaan p
WHERE p.survei_id = s.id
AND p.deleted_at IS NULL
AND p.is_required = 1) AS pertanyaan_wajib,
(SELECT COUNT(*)
FROM v2_survei_respon r
WHERE r.survei_id = s.id
AND r.deleted_at IS NULL
AND r.responden_type = 'tendik'
AND r.responden_id = 1536) AS pertanyaan_dijawab
FROM v2_survei s
WHERE s.deleted_at IS NULL;
Hasil EXPLAIN-nya:
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
1
PRIMARY
s
ALL
idx_deleted_at
NULL
NULL
NULL
48
Using where
2
DEPENDENT SUBQUERY
v2_survei_pertanyaan
ref
survei_id, idx_deleted_at
survei_id
8
survei.s.id
10
Using where
3
DEPENDENT SUBQUERY
v2_survei_respon
ref
deleted_at, responden_type, survei_id
survei_id
8
survei.s.id
26585
Using where
Ada tiga masalah yang bisa diidentifikasi:
Masalah 1: Row 3 — 26.585 baris diperiksa per subquery. Dengan 48 survei, total baris yang harus diperiksa: 48 × 26.585 = ~1,27 juta baris. Penyebabnya: index (deleted_at, responden_type, survei_id, responden_id) tidak efisien untuk query yang filter by survei_id dulu — karena survei_id bukan kolom paling kiri di index.
Masalah 2: DEPENDENT SUBQUERY di row 2 dan 3. Kedua subquery di SELECT dijalankan ulang untuk setiap baris dari v2_survei. Ini pola yang harus dihindari.
Masalah 3: Kolom key_len hanya 8. Artinya dari composite index yang tersedia, hanya satu kolom yang terpakai. Sisa kolom index sia-sia.
Perbaikan: Tambah Index yang Benar
Karena query filter by survei_id duluan, survei_id harus jadi kolom pertama di composite index:
-- Urutan kolom mengikuti urutan filter di query:
-- WHERE survei_id = ? AND deleted_at IS NULL
-- AND responden_type = ? AND responden_id = ?
ALTER TABLE v2_survei_respon
ADD INDEX idx_respon_fix (survei_id, deleted_at, responden_type, responden_id);
Perbaikan Lebih Baik: Rewrite ke JOIN
Selain menambah index, rewrite query dari DEPENDENT SUBQUERY ke JOIN bisa menghilangkan masalah secara total:
SELECT
s.nama,
COUNT(DISTINCT IF(
p.is_required = 1 AND p.deleted_at IS NULL,
p.id, NULL
)) AS pertanyaan_wajib,
COUNT(DISTINCT IF(
r.responden_type = 'tendik' AND r.responden_id = 1536
AND r.deleted_at IS NULL,
r.id, NULL
)) AS pertanyaan_dijawab
FROM v2_survei s
INNER JOIN v2_survei_pertanyaan p
ON p.survei_id = s.id
AND p.deleted_at IS NULL
AND p.jenis = 'pertanyaan'
AND p.is_required = 1
LEFT JOIN v2_survei_respon r
ON r.survei_id = s.id
AND r.deleted_at IS NULL
AND r.responden_type = 'tendik'
AND r.responden_id = 1536
AND r.pertanyaan_id = p.id
WHERE s.deleted_at IS NULL
GROUP BY s.id, s.nama;
Query ini menjalankan scan sekali saja tanpa subquery berulang. Tapi ingat, keuntungan JOIN baru terasa jika jumlah baris di tabel cukup besar — untuk tabel kecil (48 baris), perbedaan waktunya mungkin tidak signifikan.
Hubungan EXPLAIN dengan Composite Index
Setelah memahami EXPLAIN, kita bisa memverifikasi apakah composite index yang dibuat sudah optimal. Beberapa poin kunci:
Pertama, perhatikan key_len. Jika composite index punya 4 kolom tapi key_len hanya menunjukkan 1 kolom, berarti ada kolom tengah yang di-skip. Ini kembali ke aturan leftmost prefix rule — MySQL tidak bisa melompati kolom di tengah composite index.
Kedua, jika Extra menunjukkan Using intersect(), artinya MySQL harus menggabungkan dua index secara terpisah (index merge). Ini kurang efisien dibandingkan satu composite index yang menampung semua kolom filter.
Ketiga, pastikan urutan kolom di composite index sesuai dengan urutan filter di query. Jika query selalu filter survei_id dulu, survei_id harus jadi kolom pertama di index. Kalau ada query lain yang filter tanpa survei_id, buat index terpisah untuk query tersebut — satu composite index tidak bisa melayani semua pola filter.
Cheat Sheet: Membaca EXPLAIN dengan Cepat
Berikut panduan cepat untuk memeriksa hasil EXPLAIN:
Cek kolom type — pastikan bukan ALL di tabel besar
Cek kolom key — jika NULL padahal seharusnya ada index, investigasi lebih lanjut
Cek kolom rows — pastikan angka tidak mendekati total baris di tabel
Cek kolom Extra — waspadai Using temporary, Using filesort, atau Using intersect()
Cek kolom key_len — pastikan composite index terpakai penuh (bukan hanya kolom pertama)
Jika ada DEPENDENT SUBQUERY, pertimbangkan rewrite ke JOIN
Kesimpulan
EXPLAIN adalah alat wajib sebelum mengoptimasi query. Tanpa EXPLAIN, kita hanya menebak-nebak. Dengan EXPLAIN, kita bisa melihat secara persis bagaimana MySQL merencanakan eksekusi query kita — index mana yang dipakai, berapa baris yang diperiksa, dan bottleneck di mana.
Tambahan index tanpa EXPLAIN ibarat obat tanpa diagnosis — mungkin cocok, mungkin tidak. Tapi dengan EXPLAIN, kita tahu persis masalahnya dan bisa memilih solusi yang tepat: menambah index baru, memperbaiki urutan kolom composite index, atau merewrite query dari subquery ke JOIN.
Seri belajar MySQL ini terus berlanjut. Setelah memahami perbedaan single dan composite index, sekarang kita punya cara untuk memverifikasi apakah index yang dibuat benar-benar bekerja.
Komentar Terbaru