Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
205 lines (188 loc) · 9.57 KB
/
Copy pathindex.html
File metadata and controls
205 lines (188 loc) · 9.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EXPLAIN Render - visualize MySQL and PostgreSQL EXPLAIN plans</title>
<meta name="description" content="Paste the EXPLAIN output in JSON from MySQL or PostgreSQL and read the query plan as a diagram. Exports SVG and PNG, runs entirely in the browser.">
<link rel="canonical" href="https://explain-render.matob.dev/">
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#f4f6f9" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#12161c" media="(prefers-color-scheme: dark)">
<!-- Open Graph: WhatsApp, Telegram, LinkedIn, Slack, Discord, Facebook -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="EXPLAIN Render">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="https://explain-render.matob.dev/">
<meta property="og:title" content="EXPLAIN Render - SQL query plans as diagrams">
<meta property="og:description" content="Paste a MySQL or PostgreSQL EXPLAIN in JSON and read the plan as a diagram, with cost and row count on every arrow. Exports SVG and PNG, all in the browser.">
<meta property="og:image" content="https://explain-render.matob.dev/og-image.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="A MySQL query plan drawn by EXPLAIN Render: full table scan, nested loop and ORDER.">
<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="EXPLAIN Render - SQL query plans as diagrams">
<meta name="twitter:description" content="Paste a MySQL or PostgreSQL EXPLAIN in JSON and read the plan as a diagram, with cost and row count on every arrow. Exports SVG and PNG, all in the browser.">
<meta name="twitter:image" content="https://explain-render.matob.dev/og-image.png">
<meta name="twitter:image:alt" content="A MySQL query plan drawn by EXPLAIN Render: full table scan, nested loop and ORDER.">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%232f6fb0'/%3E%3Crect x='6' y='5' width='20' height='7' rx='2' fill='%23fff'/%3E%3Crect x='4' y='20' width='10' height='7' rx='2' fill='%23fff' opacity='.85'/%3E%3Crect x='18' y='20' width='10' height='7' rx='2' fill='%23fff' opacity='.85'/%3E%3Cpath d='M16 12v4M9 16h14M9 16v4M23 16v4' stroke='%23fff' stroke-width='1.8' fill='none'/%3E%3C/svg%3E">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<meta name="apple-mobile-web-app-title" content="EXPLAIN Render">
<link rel="stylesheet" href="css/style.css">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "EXPLAIN Render",
"url": "https://explain-render.matob.dev/",
"description": "Reads the EXPLAIN output of MySQL and PostgreSQL in JSON, draws the query plan as a diagram and exports it to SVG and PNG. Runs entirely in the browser.",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Any modern browser",
"browserRequirements": "Requires JavaScript",
"inLanguage": "en",
"isAccessibleForFree": true,
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"license": "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html",
"screenshot": "https://explain-render.matob.dev/og-image.png",
"featureList": [
"Reads EXPLAIN FORMAT=JSON from MySQL",
"Reads EXPLAIN (FORMAT JSON) from PostgreSQL",
"Detects the dialect automatically",
"Exports the diagram to SVG and PNG",
"With ANALYZE, compares the estimate against what happened",
"Runs in the browser, sends no data anywhere"
]
}
</script>
</head>
<body>
<header class="topbar">
<div class="brand">
<svg class="logo" viewBox="0 0 32 32" aria-hidden="true">
<rect width="32" height="32" rx="7" fill="currentColor"/>
<rect x="6" y="5" width="20" height="7" rx="2" fill="#fff"/>
<rect x="4" y="20" width="10" height="7" rx="2" fill="#fff" opacity=".85"/>
<rect x="18" y="20" width="10" height="7" rx="2" fill="#fff" opacity=".85"/>
<path d="M16 12v4M9 16h14M9 16v4M23 16v4" stroke="#fff" stroke-width="1.8" fill="none"/>
</svg>
<div class="brand-text">
<h1>EXPLAIN Render</h1>
<p>SQL query plans in JSON, drawn as diagrams, entirely in your browser</p>
</div>
</div>
<div class="topbar-actions">
<button id="btn-theme" class="icon-btn" type="button" title="Toggle light/dark theme" aria-label="Toggle theme">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
</svg>
</button>
</div>
</header>
<main class="layout">
<aside class="panel" id="panel">
<section class="panel-section">
<div class="section-head">
<h2>Plan JSON</h2>
<button id="btn-format" class="link-btn" type="button">format</button>
</div>
<textarea id="json-input" spellcheck="false" autocomplete="off" autocapitalize="off"
placeholder='Paste the output of:
MySQL EXPLAIN FORMAT=JSON SELECT ...;
PostgreSQL EXPLAIN (FORMAT JSON) SELECT ...;
The dialect is detected automatically.'></textarea>
<div class="btn-row">
<button id="btn-render" class="btn primary" type="button">Render diagram</button>
<button id="btn-clear" class="btn" type="button">Clear</button>
</div>
<p id="status" class="status" role="status"></p>
</section>
<section class="panel-section">
<div class="section-head"><h2>Samples</h2></div>
<div id="samples" class="samples"></div>
</section>
<section class="panel-section">
<div class="section-head"><h2>Options</h2></div>
<label class="check"><input type="checkbox" id="opt-cost" checked> Show cost on the arrows</label>
<label class="check"><input type="checkbox" id="opt-tooltip" checked> Details on hover</label>
<label class="check"><input type="checkbox" id="opt-auto" checked> Render as you type</label>
</section>
<section class="panel-section">
<div class="section-head"><h2 id="legend-title">Legend</h2></div>
<ul id="legend" class="legend"></ul>
</section>
<section class="panel-section help">
<div class="section-head"><h2>How to use it</h2></div>
<ol>
<li>Get the plan as JSON:
<br><code>EXPLAIN FORMAT=JSON <query>;</code> on MySQL
<br><code>EXPLAIN (FORMAT JSON) <query>;</code> on PostgreSQL
</li>
<li>Copy the result and paste it in the box above.</li>
<li>Export the diagram as SVG (vector) or PNG.</li>
</ol>
<p class="fineprint">On PostgreSQL, adding <code>ANALYZE</code> brings the real execution
numbers, and the diagram starts comparing the estimate against what happened.</p>
<p class="fineprint">Nothing is sent to any server: everything runs in your browser.</p>
</section>
</aside>
<section class="viewer">
<div class="toolbar">
<div class="tool-group">
<button id="btn-zoom-out" class="btn icon" type="button" title="Zoom out">−</button>
<span id="zoom-label" class="zoom-label">100%</span>
<button id="btn-zoom-in" class="btn icon" type="button" title="Zoom in">+</button>
<button id="btn-fit" class="btn" type="button">Fit</button>
<button id="btn-reset" class="btn" type="button">100%</button>
</div>
<div class="tool-group">
<button id="btn-copy-png" class="btn primary with-icon" type="button"
title="Copy the diagram as an image, ready to paste">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect x="9" y="9" width="12" height="12" rx="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
Copy image
</button>
<button id="btn-png" class="btn" type="button">Download PNG</button>
<button id="btn-svg" class="btn" type="button">Download SVG</button>
</div>
</div>
<div class="canvas-wrap" id="canvas-wrap">
<svg id="diagram" xmlns="http://www.w3.org/2000/svg">
<g id="viewport">
<g id="content"></g>
<g id="hits"></g>
</g>
</svg>
<div class="empty-state" id="empty-state">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="6" rx="2"/>
<rect x="2" y="15" width="8" height="6" rx="2"/>
<rect x="14" y="15" width="8" height="6" rx="2"/>
<path d="M12 9v3M6 12h12M6 12v3M18 12v3"/>
</svg>
<p>Paste the JSON of a MySQL or PostgreSQL EXPLAIN, or pick a sample.</p>
</div>
</div>
<div id="tooltip" class="tooltip" hidden></div>
</section>
</main>
<script src="js/graphics.js"></script>
<script src="js/nodes.js"></script>
<script src="js/nodes-pg.js"></script>
<script src="js/explain.js"></script>
<script src="js/explain-pg.js"></script>
<script src="js/samples.js"></script>
<script src="js/app.js"></script>
</body>
</html>