menu
languageBahasa Indonesia
save_alt Download

Explain Visualizer

Visualisasikan rencana eksekusi query sebagai diagram interaktif, dan temukan bagian query yang lambat.

oleh rathboma Plugin komunitas

Readme

Teks ini ditulis oleh pihak ketiga dan diterjemahkan secara otomatis. Baca versi asli dalam bahasa Inggris

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

Panduan: klik kanan query, buka plan-nya, jalankan Explain Analyze, dan lompat ke langkah yang lambat

  • 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 JSON PostgreSQL, tree atau JSON MySQL): klik kanan selnya;
    • plan yang tersebar di beberapa baris (output teks PostgreSQL): klik kanan header kolom QUERY PLAN;
    • tabel (EXPLAIN klasik MySQL, EXPLAIN QUERY PLAN SQLite): pilih semua baris dan kolomnya, lalu klik kanan pilihan tersebut. Untuk SQLite, kolom detail saja tetap bisa, tanpa struktur bersarang.
  • Paste Plan: tempel output EXPLAIN, misalnya dari psql, shell mysql atau sqlite3, atau dari rekan kerja.

Menu konteks query editor dengan Visualize Explain Plan

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 di-analyze dengan sequential scan dipilih beserta insight-nya

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

Tampilan tabel diurutkan berdasarkan self time

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

Plan dengan cabang CTE, InitPlan, dan SubPlan

Plugin mengikuti tema Beekeeper Studio:

Plan dalam tema terang

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/postgres mem-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/mysql mem-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, ANALYZE MariaDB, dan tabel klasik. Tes memastikan semua format konsisten.
  • tests/sqlite mem-parse baris EXPLAIN QUERY PLAN dari SQLite 3.16 (format sebelum 3.24), 3.27 dan 3.45 (tests/fixtures/sqlite).
  • tests/integration menjalankan EXPLAIN ke server live: PostgreSQL jika PG_URL diset, MySQL atau MariaDB jika MYSQL_URL diset, dan SQLite selalu, melalui node:sqlite bawaan Node.
  • tests/state menguji 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.

  1. Buat src/engines/<name>/ dengan objek yang mengimplementasikan ExplainEngine (src/engines/types.ts):
    • connectionTypes: jenis koneksi Beekeeper Studio yang ditanganinya, dan products jika mencakup beberapa (MySQL dan MariaDB).
    • inspect(sql, server): memecah dan mengklasifikasikan statement (apakah mengubah data?). src/engines/shared/lexer.ts menerima 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.ts berisi kebijakan rollback dan reads-only.
    • explain(request, runQuery): mengirim SQL apa pun yang dibutuhkan database dan mem-parse hasilnya. Fungsi ini boleh memanggil runQuery beberapa kali, misalnya untuk beralih ke format yang lebih lama.
    • loadServerInfo(runQuery): versi, dan apa pun yang perlu diketahui engine (SQL mode MySQL). Perluas ServerInfo dengan 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 dengan unavailable(server) jika membutuhkan server yang lebih baru.
  2. Petakan operator asli ke NodeKind dan isi metrik apa pun yang tersedia. Gunakan helper di src/core/metrics.ts untuk cost dan waktu jika sesuai, dan panggil finishPlan() dari src/core/analysis.ts di akhir.
  3. Daftarkan di src/engines/registry.ts, tambahkan fixture yang diambil dari server sungguhan (script capture di scripts/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 ON harus 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 ON bersama 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

  1. Jalankan bin/make-release.sh. Script ini menyarankan versi berikutnya dari tag yang ada, mengatur version di manifest.json dan package.json, melakukan commit, dan push tag yang sesuai seperti v0.1.0.
  2. Workflow rilis melakukan build, tes, dan membuat draft rilis GitHub dengan manifest.json dan explain-visualizer-<version>.zip. Publikasikan draft tersebut.

yarn build && yarn package membuat arsip yang sama secara lokal.

Lisensi

GPL-3.0. Lihat LICENSE.