Ένα plugin του Beekeeper Studio που μετατρέπει τα πλάνα εκτέλεσης query σε διαδραστικό διάγραμμα, ώστε να βρίσκεις εύκολα το αργό σημείο ενός query.

- Διάγραμμα του πλάνου, χρωματισμένο ανάλογα με το μερίδιο κάθε βήματος στον χρόνο εκτέλεσης (ή στο εκτιμώμενο κόστος). Οι φαρδύτερες συνδέσεις μεταφέρουν περισσότερες γραμμές.
- Προβολή πίνακα στο στυλ του
explain.depesz.com, με ταξινόμηση κατά ίδιο χρόνο. - Λεπτομέρειες για κάθε βήμα: ίδιος και συνολικός χρόνος, πραγματικές έναντι εκτιμώμενων γραμμών, loops, κόστη, συνθήκες, buffers, χρήση μνήμης και δίσκου, workers.
- Insights που επισημαίνουν συνηθισμένα προβλήματα: πλήρεις σαρώσεις που απορρίπτουν τις περισσότερες γραμμές, πίνακες που σαρώνονται μία φορά ανά γραμμή ενός join, sorts και hashes που χύνονται στον δίσκο, εξαρτημένα subqueries, προσωρινά indexes που χτίζει το SQLite σε κάθε εκτέλεση, μεγάλες λάθος εκτιμήσεις γραμμών και άλλα.
- Ακατέργαστη έξοδος του πλάνου, έτοιμη για αντιγραφή ή αποθήκευση.
Περισσότερα στα στιγμιότυπα παρακάτω.
Υποστηριζόμενες βάσεις δεδομένων
| Βάση δεδομένων | Explain | Explain Analyze | Επικόλληση πλάνου |
|---|---|---|---|
| PostgreSQL | Ναι | Ναι | JSON και κείμενο psql |
| MySQL | Ναι | 8.0.18+, εντολές ανάγνωσης | Tree, JSON (και οι δύο εκδόσεις) και ο κλασικός πίνακας |
| MariaDB | Ναι | 10.1+, εντολές ανάγνωσης | JSON και ο κλασικός πίνακας |
| SQLite, LibSQL | Ναι | Όχι: το SQLite δεν έχει χρονομετρήσεις βημάτων | Το δέντρο του shell sqlite3 ή οι γραμμές αποτελεσμάτων |
| SQL Server | Προγραμματισμένο |
Δοκιμασμένο με PostgreSQL 12, 17 και 18· MySQL 5.7, 8.0.17, 8.0, 8.4 και 9.7· MariaDB 10.4, 10.6 και 11.4· και SQLite 3.16, 3.27 και 3.45. Το plugin βασίζεται σε ένα μοντέλο πλάνου ανεξάρτητο από τη βάση δεδομένων, οπότε κάθε βάση χρειάζεται μόνο έναν adapter (δες Προσθήκη βάσης δεδομένων).
Χρήση
Υπάρχουν διάφοροι τρόποι:
- Επεξεργαστής query: κάνε δεξί κλικ σε ένα query και διάλεξε Visualize Explain Plan. Χρησιμοποιείται το επιλεγμένο κείμενο ή η εντολή κάτω από τον κέρσορα.
- Μενού νέας καρτέλας: άνοιξε το Explain Visualizer, γράψε μια εντολή και διάλεξε Explain ή Explain Analyze.
- Πλέγμα αποτελεσμάτων: αφού τρέξεις μόνος σου το EXPLAIN, κάνε δεξί κλικ στο πλάνο και διάλεξε Visualize Explain Plan:
- πλάνο σε ένα κελί (
FORMAT JSONτης PostgreSQL, tree ή JSON της MySQL): δεξί κλικ στο κελί· - πλάνο σε πολλές γραμμές (έξοδος κειμένου της PostgreSQL): δεξί κλικ στην κεφαλίδα της στήλης
QUERY PLAN· - πίνακας (κλασικό
EXPLAINτης MySQL,EXPLAIN QUERY PLANτου SQLite): επίλεξε όλες τις γραμμές και στήλες του και κάνε δεξί κλικ στην επιλογή. Για το SQLite αρκεί και μόνο η στήλη detail, χωρίς την ένθεση.
- πλάνο σε ένα κελί (
- Paste Plan: επικόλλησε έξοδο EXPLAIN, για παράδειγμα από το psql, το shell mysql ή sqlite3, ή από έναν συνάδελφο.

Explain και Explain Analyze
Το Explain ζητά από τη βάση δεδομένων το πλάνο της χωρίς να εκτελέσει την εντολή. Είναι πάντα ασφαλές, γι' αυτό τρέχει αυτόματα όταν η καρτέλα ανοίγει από τον επεξεργαστή.
Το Explain Analyze εκτελεί την εντολή και μετρά κάθε βήμα. Το πώς διατηρείται ασφαλές εξαρτάται από τη βάση δεδομένων, δες παρακάτω. Αν το κείμενο του επεξεργαστή ξεκινά ήδη με EXPLAIN ANALYZE (ή το αντίστοιχο της βάσης), το plugin το χρησιμοποιεί· όταν η εντολή δεν μπορεί να αναλυθεί, εκτελείται απλό explain και ο λόγος εμφανίζεται κάτω από τον επεξεργαστή.
PostgreSQL
Το plugin στέλνει EXPLAIN ANALYZE ...; ROLLBACK; ως ένα αίτημα, ώστε και οι δύο εντολές να μοιράζονται μία implicit συναλλαγή και ό,τι άλλαξε η εντολή να αναιρείται. Αυτό ισχύει και για απλά SELECT, που μπορούν να καλούν functions που γράφουν. Αν η εντολή αποτύχει, η συναλλαγή ακυρώνεται από μόνη της και η pooled σύνδεση μένει καθαρή. Επιδράσεις εκτός της συναλλαγής, όπως τιμές sequence, δεν αναιρούνται.
Οι εντολές που αλλάζουν δεδομένα (INSERT, UPDATE, DELETE, MERGE, CTE που τροποποιούν δεδομένα…) αναλύονται μόνο μετά από επιβεβαίωση. Το plugin διαβάζει την εντολή με έναν lexer που ακολουθεί τους κανόνες της ίδιας της PostgreSQL για strings, σχόλια και dollar quotes, και απορρίπτει είσοδο που περιέχει περισσότερες από μία εντολές.
Σε συνδέσεις μόνο ανάγνωσης το Beekeeper Studio δεν επιτρέπει το ROLLBACK, οπότε οι εντολές που αλλάζουν δεδομένα μπορούν μόνο να γίνουν explain και το Explain Analyze δεν τρέχει ποτέ αυτόματα. Ένα SELECT που καλεί function που γράφει δεν εντοπίζεται εκεί, όπως ακριβώς και όταν το τρέχεις σε καρτέλα query.
Το μενού Options ενεργοποιεί/απενεργοποιεί τα BUFFERS, VERBOSE, SETTINGS και WAL. Οι επιλογές που δεν υποστηρίζει ο server είναι απενεργοποιημένες. Οι εντολές με παραμέτρους $1 γίνονται explain με GENERIC_PLAN σε PostgreSQL 16+.
MySQL και MariaDB
Το plugin διαβάζει την έκδοση του server και χρησιμοποιεί τη νεότερη μορφή πλάνου που διαθέτει:
| Server | Explain | Explain Analyze |
|---|---|---|
| MySQL 8.0.18+ | EXPLAIN FORMAT=TREE |
EXPLAIN ANALYZE |
| MySQL 5.6 έως 8.0.17 | EXPLAIN FORMAT=JSON |
Μη διαθέσιμο |
| MariaDB 10.1+ | EXPLAIN FORMAT=JSON |
ANALYZE FORMAT=JSON |
| Παλαιότεροι servers | Ο κλασικός πίνακας EXPLAIN |
Μη διαθέσιμο |
Τα UPDATE και DELETE ενός πίνακα δεν έχουν tree· το plugin καταφεύγει στο FORMAT=JSON και, στη MySQL 9, της οποίας το JSON δεν μπορεί να τα δείξει ούτε αυτό, στον κλασικό πίνακα. Το TiDB αναγνωρίζεται και απορρίπτεται αντί να διαβαστεί λάθος.
Το Explain Analyze εκτελεί μόνο εντολές ανάγνωσης. Σε αντίθεση με την PostgreSQL, δεν μπορείς να βασιστείς στη MySQL για να αναιρέσει ένα αποτυχημένο αίτημα: αν σταλεί ως START TRANSACTION; ...; ROLLBACK;, μια εντολή που απέτυχε θα άφηνε τη συναλλαγή ανοιχτή σε μια pooled σύνδεση που χρησιμοποιούν μετά άλλες καρτέλες. Ένα SELECT που καλεί stored function που γράφει κάνει commit ό,τι έκανε η function, όπως ακριβώς όταν το τρέχεις σε καρτέλα query. Στη MariaDB, η λειτουργία μόνο ανάγνωσης του Beekeeper Studio απορρίπτει την εντολή ANALYZE, οπότε το Explain Analyze δεν είναι διαθέσιμο σε συνδέσεις μόνο ανάγνωσης.
Η εντολή διαβάζεται με τους κανόνες της MySQL: σχόλια # και -- που τελειώνουν μόνο σε line feed, backslash escapes, strings "..." και σχόλια /*! ... */, των οποίων το περιεχόμενο εκτελεί η MySQL. Τα NO_BACKSLASH_ESCAPES και ANSI_QUOTES αλλάζουν το πού τελειώνουν τα strings, και μια pooled σύνδεση μπορεί να έχει οποιοδήποτε από τα δύο, οπότε μια εντολή πρέπει να διαβάζεται ως μία εντολή, και ως ανάγνωση, σε κάθε συνδυασμό τους. Κείμενο που ένας server μπορεί να διαβάσει με περισσότερους από έναν τρόπους απορρίπτεται αντί να γίνει εικασία: ένα σχόλιο /*!50700 ... */ που εξαρτάται από την έκδοση ή ένα /*M! ... */ μόνο για MariaDB, ένα carriage return μέσα σε σχόλιο -- ή ένας χαρακτήρας NUL.
Η MariaDB χρονομετρά κάθε πίνακα αντί για κάθε βήμα, οπότε ο χρόνος ενός join ή ενός προσωρινού πίνακα είναι ό,τι χρειάστηκε το query πέρα από τους πίνακες που διάβασε.
SQLite
Το EXPLAIN QUERY PLAN δείχνει ποιοι πίνακες διαβάζονται, με ποια σειρά και με ποιο index. Το SQLite δεν αναφέρει κόστη, πλήθος γραμμών ή χρόνους, οπότε το διάγραμμα δείχνει τα βήματα και η προβολή πίνακα τις λεπτομέρειές τους, και δεν υπάρχει Explain Analyze. Τα insights επισημαίνουν προσωρινά indexes που χτίζει το SQLite σε κάθε εκτέλεση, πίνακες που σαρώνονται μία φορά ανά γραμμή ενός join ή correlated subquery, και sorts σε προσωρινό B-tree. Οι συνδέσεις LibSQL χρησιμοποιούν την ίδια μηχανή.
Το Beekeeper Studio χωρίζει το κείμενο SQLite σε εντολές με τον δικό του parser πριν τις εκτελέσει, οπότε μια εντολή με ερωτηματικό μέσα της (σε string, όνομα ή σχόλιο) απορρίπτεται: έτσι κανένας splitter δεν μπορεί να βρει δεύτερη εντολή μέσα της.
Στιγμιότυπα
Explain Analyze, με επιλεγμένο το αργό βήμα και ένα insight γι' αυτό:

Το ίδιο πλάνο ως πίνακας, ταξινομημένο κατά ίδιο χρόνο:

Ένα query με CTE, InitPlan και SubPlan, το καθένα ως ξεχωριστός κλάδος:

Το plugin ακολουθεί το θέμα του Beekeeper Studio:

Ανάπτυξη
Απαιτεί Node.js 22+ και 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 χρησιμοποιεί το @beekeeperstudio/vite-plugin, που δημιουργεί symlink αυτού του φακέλου στον κατάλογο plugins του Beekeeper Studio.
Από προεπιλογή το Beekeeper Studio φορτώνει μόνο τα δικά του εγκεκριμένα plugins. Για να φορτώσεις αυτό, πρόσθεσε τα παρακάτω στο αρχείο ρυθμίσεων χρήστη και κάνε επανεκκίνηση της εφαρμογής:
[pluginSystem]
disabled = false
Μετά σύνδεσε μια βάση δεδομένων: το Visualize Explain Plan εμφανίζεται στο μενού περιβάλλοντος του επεξεργαστή query και το Explain Visualizer στο μενού νέας καρτέλας.
Harness
Το dev/harness.html παίζει τον ρόλο του Beekeeper Studio: φορτώνει το plugin σε ένα iframe και απαντά στα αιτήματά του με τα ίδια μηνύματα που χρησιμοποιεί η εφαρμογή, εκτελώντας queries σε πραγματικές βάσεις δεδομένων. Είναι ο πιο γρήγορος τρόπος να δουλέψεις στο UI, να δοκιμάσεις κάθε τρόπο ανοίγματος της καρτέλας, να αλλάξεις βάσεις δεδομένων και θέματα.
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 κατευθύνει τη MariaDB του harness σε άλλον server (διαφορετικά χρησιμοποιεί το MYSQL_URL). Το SQLite δεν χρειάζεται τίποτα: μια προσωρινή βάση δεδομένων γεμίζει από το scripts/fixtures/seed-sqlite.sql στην πρώτη χρήση, ή το SQLITE_PATH ορίζει μία.
Tests
- Το
tests/postgresαναλύει πραγματικά πλάνα από PostgreSQL 12, 17 και 18 (tests/fixtures/postgres). Κάθε fixture έχει το ίδιο πλάνο σε μορφή JSON και κειμένου, και τα tests ελέγχουν ότι και τα δύο παράγουν το ίδιο δέντρο. - Το
tests/mysqlαναλύει πλάνα από MySQL 5.7, 8.0.17, 8.0, 8.4 και 9.7 και MariaDB 10.4, 10.6 και 11.4 (tests/fixtures/mysql). Κάθε fixture έχει κάθε μορφή που διαθέτει ο server του για μία εντολή: tree,EXPLAIN ANALYZE, και τις δύο εκδόσεις JSON, τοANALYZEτης MariaDB και τον κλασικό πίνακα. Τα tests ελέγχουν ότι οι μορφές συμφωνούν. - Το
tests/sqliteαναλύει γραμμέςEXPLAIN QUERY PLANαπό SQLite 3.16 (η μορφή πριν το 3.24), 3.27 και 3.45 (tests/fixtures/sqlite). - Το
tests/integrationεκτελεί EXPLAIN σε ζωντανούς servers: PostgreSQL όταν έχει οριστεί τοPG_URL, MySQL ή MariaDB όταν έχει οριστεί τοMYSQL_URL, και SQLite πάντα, μέσω του ενσωματωμένουnode:sqliteτου Node. - Το
tests/stateκαλύπτει τη συμπεριφορά της καρτέλας με έναν ψεύτικο host.
Για να καταγράψεις fixtures από άλλη έκδοση server, γέμισέ τον με δεδομένα και τρέξε το script καταγραφής του:
# 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
Πώς λειτουργεί
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
Κάθε adapter μετατρέπει την έξοδο EXPLAIN της βάσης του στο μοντέλο Plan στο src/core/plan.ts. Ένα PlanNode έχει όνομα λειτουργίας, ένα kind (scan, index, join, filter, sort…), προαιρετικές εκτιμήσεις (totalCost, estimatedRows), προαιρετικές μετρήσεις (actualRows, loops, χρόνους), παράγωγα inclusiveTime, exclusiveTime και exclusiveCost, καθώς και συνθήκες και ομαδοποιημένες ιδιότητες για το πάνελ λεπτομερειών. Κάθε μετρική είναι προαιρετική και το UI δείχνει μόνο ό,τι παρέχει η μηχανή: ένα πλάνο SQLite δεν έχει αριθμούς, οπότε ο πίνακας δείχνει τις λεπτομέρειες κάθε βήματος αντί για κόστη.
Ο ίδιος χρόνος εξαρτάται από τη μηχανή, γι' αυτό τον υπολογίζει ο adapter. Οι κανόνες της PostgreSQL βρίσκονται στο src/engines/postgres/timing.ts: οι χρόνοι ανά loop πολλαπλασιάζονται με τα loops, οι parallel workers μετριούνται μία φορά, ο χρόνος των CTE χρεώνεται στα CTE scans που τα διαβάζουν και ο χρόνος ενός InitPlan χρεώνεται στον κόμβο που το αποτιμά. Η MySQL αναφέρει επίσης χρόνους ανά loop και χρησιμοποιεί το κοινό computeLoopTimings (src/core/metrics.ts), με τα subqueries της λίστας select να προστίθενται πάνω από το query, που δεν τα περιλαμβάνει. Η MariaDB χρονομετρά πίνακες και ολόκληρα queries, όχι βήματα· το computeMixedTimings συμπληρώνει τα υπόλοιπα.
Οι τρεις μορφές της MySQL διαβάζονται στα ίδια ονόματα λειτουργιών: το κείμενο tree και το JSON έκδοσης 2 απαριθμούν τους ίδιους iterators, και το query-block JSON (και ο κλασικός πίνακας, που ανακατασκευάζεται σε αυτό) γίνεται αλυσίδα από joins με τη σειρά των πινάκων. Οι κανόνες των insights δουλεύουν πάνω σε αυτά τα ονόματα, όχι στην εγγενή έξοδο.
Το src/core/analysis.ts προσθέτει ό,τι είναι κοινό σε όλες τις μηχανές: μερίδια χρόνου και κόστους, τα πιο αργά βήματα και insights για λάθος εκτιμήσεις γραμμών.
Προσθήκη βάσης δεδομένων
Δεν χρειάζεται να αλλάξει τίποτα εκτός από τον φάκελο της μηχανής και το registry.
- Δημιούργησε το
src/engines/<name>/με ένα αντικείμενο που υλοποιεί τοExplainEngine(src/engines/types.ts):connectionTypes: οι τύποι σύνδεσης του Beekeeper Studio που χειρίζεται, καιproductsόταν καλύπτει πολλούς (MySQL και MariaDB).inspect(sql, server): διαχωρίζει και κατηγοριοποιεί την εντολή (αλλάζει δεδομένα;). Τοsrc/engines/shared/lexer.tsδέχεται μια διάλεκτο: στυλ σχολίων, quotes, placeholders.analyzePolicy(statement, context): αν το Explain Analyze μπορεί να την εκτελέσει, τι να ρωτήσει πρώτα και τι να γράψει κάτω από τον επεξεργαστή. Τοsrc/engines/shared/analyzePolicy.tsέχει τις πολιτικές rollback και μόνο ανάγνωσης.explain(request, runQuery): στέλνει όποιο SQL χρειάζεται η βάση δεδομένων και αναλύει το αποτέλεσμα. Μπορεί να καλέσει τοrunQueryαρκετές φορές, για παράδειγμα για να καταφύγει σε παλαιότερη μορφή.loadServerInfo(runQuery): η έκδοση και οτιδήποτε άλλο χρειάζεται να ξέρει η μηχανή (το SQL mode της MySQL). Επέκτεινε τοServerInfoμε τα δικά σου πεδία.canParse/parse: διαβάζουν επικολλημένη έξοδο και τιμές από το πλέγμα αποτελεσμάτων. Το ακατέργαστο κείμενο που επιστρέφει ένα parse πρέπει να αναλύεται ξανά στο ίδιο πλάνο: οι καρτέλες που επαναφέρονται ανακατασκευάζονται από αυτό.options: διακόπτες που εμφανίζονται στο μενού Options, ο καθένας μεunavailable(server)όταν χρειάζεται νεότερο server.
- Αντιστοίχισε τους εγγενείς τελεστές σε
NodeKindκαι συμπλήρωσε όποιες μετρικές υπάρχουν. Χρησιμοποίησε τα helpers στοsrc/core/metrics.tsγια κόστη και χρόνους όπου ταιριάζουν και κάλεσε τοfinishPlan()από τοsrc/core/analysis.tsστο τέλος. - Κάνε την εγγραφή στο
src/engines/registry.ts, πρόσθεσε fixtures από πραγματικούς servers (ένα script καταγραφής στοscripts/fixtures/) και tests όπως τα υπόλοιπα.
Σημειώσεις για τον SQL Server, που είναι προγραμματισμένος:
- Ο client SQL Server του Beekeeper Studio χωρίζει ένα αίτημα στο
;και μπορεί να εκτελέσει κάθε εντολή σε διαφορετική pooled σύνδεση. ΤοSET SHOWPLAN_XML ONπρέπει να είναι μόνο του στο batch του και ισχύει για το επόμενο batch στην ίδια σύνδεση, οπότε ένα εκτιμώμενο πλάνο χρειάζεται νέο host API που εκτελεί batches σε μία σύνδεση. - Το
SET STATISTICS XML ONμε την εντολή σε ένα batch (χωρίς;) δίνει το πραγματικό πλάνο, αλλά εκτελεί την εντολή και επιστρέφει τις γραμμές της στο plugin. - Το XML πλάνου που επικολλάται από το SSMS (
.sqlplan) δεν χρειάζεται υποστήριξη από τον host.
Κυκλοφορία εκδόσεων
- Τρέξε το
bin/make-release.sh. Προτείνει την επόμενη έκδοση από τα υπάρχοντα tags, ορίζει τοversionσταmanifest.jsonκαιpackage.json, κάνει commit και push ένα αντίστοιχο tag όπωςv0.1.0. - Το release workflow κάνει build, τρέχει τα tests και δημιουργεί ένα draft GitHub release με τα
manifest.jsonκαιexplain-visualizer-<version>.zip. Δημοσίευσε το draft.
Το yarn build && yarn package δημιουργεί το ίδιο αρχείο τοπικά.
Άδεια
GPL-3.0. Δες το LICENSE.