Plugin Beekeeper Studio yang mengubah rencana eksekusi query menjadi diagram interaktif, sehingga bagian query yang lambat mudah ditemukan.

- Diagram plan, diwarnai sesuai porsi waktu eksekusi (atau estimasi cost) tiap langkah. Garis penghubung yang lebih lebar membawa lebih banyak baris.
- Tampilan tabel ala
explain.depesz.com, bisa diurutkan berdasarkan self time. - Detail untuk setiap langkah: self time dan total time, baris aktual vs. estimasi, loop, cost, kondisi, buffer, penggunaan memori dan disk, worker.
- Insight yang menunjukkan masalah umum: full scan yang membuang sebagian besar baris, tabel yang di-scan sekali per baris join, sort dan hash yang tumpah ke disk, dependent subquery, indeks sementara yang dibuat SQLite di setiap eksekusi, selisih estimasi baris yang besar, dan lainnya.
- Output plan mentah, siap disalin atau disimpan.
Selengkapnya di screenshot di bawah.
Database yang didukung
| Database | Explain | Explain Analyze | Tempel plan |
|---|---|---|---|
| PostgreSQL | Ya | Ya | JSON dan teks psql |
| MySQL | Ya | 8.0.18+, statement yang membaca data | Tree, JSON (kedua versi) dan tabel klasik |
| MariaDB | Ya | 10.1+, statement yang membaca data | JSON dan tabel klasik |
| SQLite, LibSQL | Ya | Tidak: SQLite tidak punya timing per langkah | Tree dari shell sqlite3, atau baris hasil |
| SQL Server | Direncanakan |
Diuji dengan PostgreSQL 12, 17 dan 18; MySQL 5.7, 8.0.17, 8.0, 8.4 dan 9.7; MariaDB 10.4, 10.6 dan 11.4; serta SQLite 3.16, 3.27 dan 3.45. Plugin ini dibangun di atas model plan yang netral terhadap database, sehingga setiap database hanya membutuhkan adapter (lihat Menambahkan database).
Cara menggunakan
Ada beberapa cara membukanya:
- Query editor: klik kanan sebuah query dan pilih Visualize Explain Plan. Teks yang dipilih akan digunakan, atau statement di bawah kursor.
- Menu tab baru: buka Explain Visualizer, tulis statement, lalu pilih Explain atau Explain Analyze.
- Grid hasil: setelah menjalankan EXPLAIN sendiri, klik kanan plan-nya dan pilih Visualize Explain Plan:
- plan dalam satu sel (
FORMAT JSONPostgreSQL, tree atau JSON MySQL): klik kanan selnya; - plan yang tersebar di beberapa baris (output teks PostgreSQL): klik kanan header kolom
QUERY PLAN; - tabel (
EXPLAINklasik MySQL,EXPLAIN QUERY PLANSQLite): pilih semua baris dan kolomnya, lalu klik kanan pilihan tersebut. Untuk SQLite, kolom detail saja tetap bisa, tanpa struktur bersarang.
- plan dalam satu sel (
- Paste Plan: tempel output EXPLAIN, misalnya dari psql, shell mysql atau sqlite3, atau dari rekan kerja.

Explain dan Explain Analyze
Explain meminta plan dari database tanpa menjalankan statement-nya. Ini selalu aman, jadi otomatis dijalankan saat tab dibuka dari editor.
Explain Analyze menjalankan statement dan mengukur setiap langkah. Cara menjaganya tetap aman tergantung database, lihat di bawah. Jika teks editor sudah diawali EXPLAIN ANALYZE (atau padanannya di database tersebut), plugin akan memakainya; jika statement tidak bisa di-analyze, statement tersebut di-explain saja, dan alasannya ditampilkan di bawah editor.
PostgreSQL
Plugin mengirim EXPLAIN ANALYZE ...; ROLLBACK; sebagai satu request, sehingga kedua statement berbagi satu transaksi implisit dan semua perubahan dari statement tersebut di-rollback. Termasuk SELECT biasa, yang bisa memanggil fungsi yang menulis data. Jika statement gagal, transaksi otomatis dibatalkan dan koneksi pool tetap bersih. Efek di luar transaksi, seperti nilai sequence, tidak dikembalikan.
Statement yang mengubah data (INSERT, UPDATE, DELETE, MERGE, CTE yang memodifikasi data…) hanya di-analyze setelah konfirmasi. Plugin membaca statement dengan lexer yang mengikuti aturan PostgreSQL sendiri untuk string, komentar, dan dollar quote, serta menolak input yang berisi lebih dari satu statement.
Pada koneksi read-only, Beekeeper Studio tidak mengizinkan ROLLBACK, sehingga statement yang mengubah data hanya bisa di-explain, dan Explain Analyze tidak pernah berjalan otomatis. SELECT yang memanggil fungsi yang menulis data tidak terdeteksi di sana, sama seperti saat menjalankannya di tab query.
Menu Options mengaktifkan/menonaktifkan BUFFERS, VERBOSE, SETTINGS dan WAL. Opsi yang tidak didukung server akan dinonaktifkan. Statement dengan parameter $1 di-explain dengan GENERIC_PLAN di PostgreSQL 16+.
MySQL dan MariaDB
Plugin membaca versi server dan memakai format plan terbaru yang tersedia:
| Server | Explain | Explain Analyze |
|---|---|---|
| MySQL 8.0.18+ | EXPLAIN FORMAT=TREE |
EXPLAIN ANALYZE |
| MySQL 5.6 hingga 8.0.17 | EXPLAIN FORMAT=JSON |
Tidak tersedia |
| MariaDB 10.1+ | EXPLAIN FORMAT=JSON |
ANALYZE FORMAT=JSON |
| Server lama | Tabel EXPLAIN klasik |
Tidak tersedia |
UPDATE dan DELETE satu tabel tidak punya tree; plugin beralih ke FORMAT=JSON, dan di MySQL 9, yang JSON-nya juga tidak bisa menampilkannya, ke tabel klasik. TiDB dikenali dan ditolak, alih-alih dibaca dengan keliru.
Explain Analyze hanya menjalankan statement yang membaca data. Tidak seperti PostgreSQL, MySQL tidak bisa diandalkan untuk membatalkan request yang gagal: jika dikirim sebagai START TRANSACTION; ...; ROLLBACK;, statement yang gagal akan membiarkan transaksi terbuka di koneksi pool yang kemudian dipakai tab lain. SELECT yang memanggil stored function yang menulis data akan meng-commit apa yang dilakukan fungsi tersebut, sama seperti menjalankannya di tab query. Di MariaDB, mode read-only Beekeeper Studio menolak statement ANALYZE, sehingga Explain Analyze tidak tersedia di koneksi read-only.
Statement dibaca dengan aturan MySQL: komentar # dan -- yang hanya berakhir di line feed, escape backslash, string "...", dan komentar /*! ... */, yang isinya dijalankan MySQL. NO_BACKSLASH_ESCAPES dan ANSI_QUOTES mengubah cara string berakhir, dan koneksi pool bisa memiliki salah satunya, sehingga statement harus terbaca sebagai satu statement, dan sebagai operasi baca, di setiap kombinasinya. Teks yang bisa dibaca server dengan lebih dari satu cara ditolak, bukan ditebak: komentar /*!50700 ... */ yang bergantung versi atau /*M! ... */ khusus MariaDB, carriage return di dalam komentar --, atau karakter NUL.
MariaDB mengukur waktu per tabel, bukan per langkah, sehingga waktu sebuah join atau tabel sementara adalah waktu yang dibutuhkan query di luar tabel-tabel yang dibacanya.
SQLite
EXPLAIN QUERY PLAN menunjukkan tabel mana yang dibaca, dalam urutan apa, dan dengan indeks apa. SQLite tidak melaporkan cost, jumlah baris, atau timing, jadi diagram menampilkan langkah-langkahnya dan tampilan tabel menampilkan detailnya, serta tidak ada Explain Analyze. Insight menunjukkan indeks sementara yang dibuat SQLite di setiap eksekusi, tabel yang di-scan sekali per baris join atau correlated subquery, dan sort di B-tree sementara. Koneksi LibSQL memakai engine yang sama.
Beekeeper Studio memecah teks SQLite menjadi statement dengan parser-nya sendiri sebelum menjalankannya, jadi statement yang mengandung titik koma (di dalam string, nama, atau komentar) ditolak: dengan begitu tidak ada splitter yang bisa menemukan statement kedua di dalamnya.
Screenshot
Explain Analyze, dengan langkah lambat dipilih beserta insight-nya:

Plan yang sama dalam bentuk tabel, diurutkan berdasarkan self time:

Query dengan CTE, InitPlan, dan SubPlan, masing-masing ditampilkan sebagai cabang sendiri:

Plugin mengikuti tema Beekeeper Studio:

Pengembangan
Membutuhkan Node.js 22+ dan Yarn 1.
yarn install
yarn dev # builds with hot reload and links the plugin into Beekeeper Studio
yarn test # unit tests
yarn build # type-check and build into dist/
yarn dev memakai @beekeeperstudio/vite-plugin, yang membuat symlink folder ini ke direktori plugin Beekeeper Studio.
Secara default Beekeeper Studio hanya memuat plugin yang ada di allow-list-nya. Untuk memuat plugin ini, tambahkan baris berikut ke file konfigurasi pengguna Anda dan restart aplikasi:
[pluginSystem]
disabled = false
Lalu hubungkan ke database: Visualize Explain Plan muncul di menu konteks query editor dan Explain Visualizer di menu tab baru.
Harness
dev/harness.html menggantikan Beekeeper Studio: file ini memuat plugin di iframe dan menjawab request-nya dengan pesan yang sama seperti yang dipakai aplikasi, menjalankan query ke database sungguhan. Ini cara tercepat untuk mengerjakan UI, mencoba semua cara membuka tab, berganti database, dan berganti tema.
docker run -d --name pg -e POSTGRES_PASSWORD=pw -p 5432:5432 postgres:17
psql postgres://postgres:pw@localhost:5432/postgres -f scripts/fixtures/seed.sql
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=pw -e MYSQL_DATABASE=shop -p 3306:3306 mysql:8.4
mysql -h127.0.0.1 -uroot -ppw shop < scripts/fixtures/seed-mysql.sql
PG_URL=postgres://postgres:pw@localhost:5432/postgres \
MYSQL_URL=mysql://root:pw@127.0.0.1:3306/shop \
yarn harness
MARIADB_URL mengarahkan MariaDB milik harness ke server lain (jika tidak, dipakai MYSQL_URL). SQLite tidak butuh apa-apa: database sementara diisi dari scripts/fixtures/seed-sqlite.sql saat pertama dipakai, atau SQLITE_PATH menunjuk ke database tertentu.
Tes
tests/postgresmem-parse plan asli yang diambil dari PostgreSQL 12, 17 dan 18 (tests/fixtures/postgres). Setiap fixture berisi plan yang sama dalam bentuk JSON dan teks, dan tes memastikan keduanya menghasilkan tree yang sama.tests/mysqlmem-parse plan yang diambil dari MySQL 5.7, 8.0.17, 8.0, 8.4 dan 9.7 serta MariaDB 10.4, 10.6 dan 11.4 (tests/fixtures/mysql). Setiap fixture berisi semua format yang dimiliki server-nya untuk satu statement: tree,EXPLAIN ANALYZE, kedua versi JSON,ANALYZEMariaDB, dan tabel klasik. Tes memastikan semua format konsisten.tests/sqlitemem-parse barisEXPLAIN QUERY PLANdari SQLite 3.16 (format sebelum 3.24), 3.27 dan 3.45 (tests/fixtures/sqlite).tests/integrationmenjalankan EXPLAIN ke server live: PostgreSQL jikaPG_URLdiset, MySQL atau MariaDB jikaMYSQL_URLdiset, dan SQLite selalu, melaluinode:sqlitebawaan Node.tests/statemenguji perilaku tab dengan host tiruan.
Untuk mengambil fixture dari versi server lain, isi datanya dan jalankan script capture-nya:
# PostgreSQL: seed with scripts/fixtures/seed.sql
PG_URL=postgres://... FIXTURE_PREFIX=pg16- node scripts/fixtures/capture-postgres.mjs
# MySQL or MariaDB: seed with scripts/fixtures/seed-mysql.sql; named after the server
MYSQL_URL=mysql://root:pw@127.0.0.1:3306/shop node scripts/fixtures/capture-mysql.mjs
# SQLite: uses Python's bundled SQLite, so older Python images give older SQLite
python3 scripts/fixtures/capture-sqlite.py
docker run --rm -v "$PWD:/w" -w /w python:3.6-stretch python3 scripts/fixtures/capture-sqlite.py
Cara kerjanya
src/
core/ database-neutral plan model, analysis, metrics, layout, formatting
engines/ one adapter per database family, plus the registry
postgres/ EXPLAIN builder, JSON and text parsers, timing rules, insights
mysql/ version detection; tree, JSON (both versions) and table readers; insights
sqlite/ EXPLAIN QUERY PLAN rows and shell text; insights
shared/ helpers adapters build on: a configurable SQL lexer, statement
checks, Explain Analyze policies, result readers, a JSON parser
that keeps repeated keys
host/ everything that talks to Beekeeper Studio
state/ the tab's state and actions
components/ Vue components: diagram, table, details, raw view
Setiap adapter mengonversi output EXPLAIN database-nya ke model Plan di src/core/plan.ts. Sebuah PlanNode memiliki nama operasi, kind (scan, index, join, filter, sort…), estimasi opsional (totalCost, estimatedRows), pengukuran opsional (actualRows, loops, waktu), turunan inclusiveTime, exclusiveTime dan exclusiveCost, plus kondisi dan properti terkelompok untuk panel detail. Setiap metrik bersifat opsional, dan UI hanya menampilkan apa yang disediakan engine: plan SQLite tidak punya angka, jadi tabel menampilkan detail tiap langkah, bukan cost.
Self time bergantung pada engine, jadi adapter yang menghitungnya. Aturan PostgreSQL ada di src/engines/postgres/timing.ts: waktu per loop dikalikan jumlah loop, parallel worker dihitung sekali, waktu CTE dibebankan ke CTE scan yang membacanya, dan waktu InitPlan dibebankan ke node yang mengevaluasinya. MySQL juga melaporkan waktu per loop dan memakai computeLoopTimings bersama (src/core/metrics.ts), dengan subquery di select list ditambahkan di atas query, yang tidak menyertakannya. MariaDB mengukur waktu tabel dan keseluruhan query, bukan langkah; computeMixedTimings melengkapi sisanya.
Ketiga format MySQL dibaca menjadi nama operasi yang sama: teks tree dan JSON versi 2 mencantumkan iterator yang sama, dan JSON query-block (serta tabel klasik, yang disusun ulang ke dalamnya) menjadi rangkaian join sesuai urutan tabel. Aturan insight bekerja pada nama-nama tersebut, bukan pada output aslinya.
src/core/analysis.ts menambahkan hal yang sama untuk semua engine: porsi waktu dan cost, langkah paling lambat, dan insight selisih estimasi baris.
Menambahkan database
Tidak ada yang perlu diubah di luar folder engine dan registry.
- Buat
src/engines/<name>/dengan objek yang mengimplementasikanExplainEngine(src/engines/types.ts):connectionTypes: jenis koneksi Beekeeper Studio yang ditanganinya, danproductsjika mencakup beberapa (MySQL dan MariaDB).inspect(sql, server): memecah dan mengklasifikasikan statement (apakah mengubah data?).src/engines/shared/lexer.tsmenerima dialek: gaya komentar, tanda kutip, placeholder.analyzePolicy(statement, context): apakah Explain Analyze boleh menjalankannya, apa yang ditanyakan terlebih dulu, dan apa yang ditampilkan di bawah editor.src/engines/shared/analyzePolicy.tsberisi kebijakan rollback dan reads-only.explain(request, runQuery): mengirim SQL apa pun yang dibutuhkan database dan mem-parse hasilnya. Fungsi ini boleh memanggilrunQuerybeberapa kali, misalnya untuk beralih ke format yang lebih lama.loadServerInfo(runQuery): versi, dan apa pun yang perlu diketahui engine (SQL mode MySQL). PerluasServerInfodengan field Anda sendiri.canParse/parse: membaca output yang ditempel dan nilai dari grid hasil. Teks mentah yang dikembalikan parse harus bisa di-parse kembali menjadi plan yang sama: tab yang dipulihkan dibangun ulang darinya.options: toggle yang ditampilkan di menu Options, masing-masing denganunavailable(server)jika membutuhkan server yang lebih baru.
- Petakan operator asli ke
NodeKinddan isi metrik apa pun yang tersedia. Gunakan helper disrc/core/metrics.tsuntuk cost dan waktu jika sesuai, dan panggilfinishPlan()darisrc/core/analysis.tsdi akhir. - Daftarkan di
src/engines/registry.ts, tambahkan fixture yang diambil dari server sungguhan (script capture discripts/fixtures/) dan tes seperti yang lain.
Catatan untuk SQL Server, yang sedang direncanakan:
- Client SQL Server di Beekeeper Studio memecah request berdasarkan
;dan bisa menjalankan setiap statement di koneksi pool yang berbeda.SET SHOWPLAN_XML ONharus sendirian di batch-nya dan berlaku untuk batch berikutnya di koneksi yang sama, jadi estimated plan membutuhkan API host baru yang menjalankan batch di satu koneksi. SET STATISTICS XML ONbersama statement dalam satu batch (tanpa;) memberikan actual plan, tetapi menjalankan statement dan mengembalikan barisnya ke plugin.- XML plan yang ditempel dari SSMS (
.sqlplan) tidak membutuhkan dukungan host.
Merilis
- Jalankan
bin/make-release.sh. Script ini menyarankan versi berikutnya dari tag yang ada, mengaturversiondimanifest.jsondanpackage.json, melakukan commit, dan push tag yang sesuai sepertiv0.1.0. - Workflow rilis melakukan build, tes, dan membuat draft rilis GitHub dengan
manifest.jsondanexplain-visualizer-<version>.zip. Publikasikan draft tersebut.
yarn build && yarn package membuat arsip yang sama secara lokal.
Lisensi
GPL-3.0. Lihat LICENSE.