Show details Citus query plan instead of just 'Custom Scan'
parent
91ad54d17b
commit
58b71804d8
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg2"
|
||||
sodipodi:docname="ex_citus.svg"
|
||||
inkscape:version="1.4 (e7c3feb1, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="namedview2"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="2.368263"
|
||||
inkscape:cx="-1.055626"
|
||||
inkscape:cy="63.970936"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="786"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<path
|
||||
fill="#1b324f"
|
||||
d="M 39.722625,27.973765 C 40.337554,24.89912 31.523573,23.600937 26.467491,29.818551 20.79648,36.787746 32.206827,44.098567 45.18866,34.32803 53.456038,28.04209 56.12073,19.433085 51.269624,15.060257 41.840714,6.4512526 19.020018,14.445328 11.36757,31.526687 19.020018,18.61318 38.219466,12.532216 45.871914,20.389641 c 3.211296,3.279621 1.434835,9.907188 -4.441153,12.708531 -9.497235,4.441154 -8.609005,-5.261058 -1.708136,-5.124407"
|
||||
id="path1"
|
||||
style="stroke-width:0.683254" />
|
||||
<path
|
||||
fill="#239646"
|
||||
d="M 39.244347,21.209547 C 23.529497,16.495092 2.2119613,35.762864 13.144031,48.471395 20.386527,56.943749 45.735264,52.844223 53.86599,27.29051 44.232104,44.918473 26.057538,47.514839 19.156669,42.458757 11.025942,36.514444 21.138107,19.843038 39.244347,21.209547"
|
||||
id="path2"
|
||||
style="stroke-width:0.683254" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-5{fill:#34495e;}
|
||||
.cls-6{fill:none;stroke-linecap:round;}
|
||||
.cls-5,.cls-6{stroke-linejoin:round;stroke:#34495e;}
|
||||
</style>
|
||||
</defs>
|
||||
<polygon class="cls-5" transform="translate(8)" points="43.3 54.7 42.3 51.6 40 54.8"/>
|
||||
<line class="cls-6" x1="49.6" x2="41.5" y1="53.3" y2="47.6"/>
|
||||
<polygon class="cls-5" transform="translate(8)" points="43.3 9.32 42.3 12.4 40 9.21"/>
|
||||
<line class="cls-6" x1="49.6" x2="41.5" y1="10.6" y2="16.4"/>
|
||||
<polygon class="cls-5" transform="translate(8)" points="45.4 31.6 42.8 29.6 42.8 33.6"/>
|
||||
<line class="cls-6" x1="51.2" x2="41.4" y1="31.5" y2="31.5"/>
|
||||
<polygon class="cls-5" transform="translate(8)" points="45 19 41.9 18 43.2 21.7"/>
|
||||
<line class="cls-6" x1="51" x2="41.6" y1="19.6" y2="23"/>
|
||||
<polygon class="cls-5" transform="translate(8)" points="45 43.5 41.9 44.4 43.2 40.7"/>
|
||||
<line class="cls-6" x1="51" x2="41.6" y1="42.8" y2="39.5"/>
|
||||
<g transform="translate(51.6 26.3)">
|
||||
<path d="m-23.3 3.39c0.389-1.95-5.19-2.77-8.39 1.17-3.59 4.41 3.63 9.04 11.9 2.86 5.24-3.98 6.92-9.43 3.85-12.2-5.97-5.45-20.4-0.389-25.3 10.4 4.85-8.18 17-12 21.8-7.05 2.03 2.08 0.909 6.27-2.81 8.05-6.01 2.81-5.45-3.33-1.08-3.25" fill="#1b324f" style="stroke-width:.433"/>
|
||||
<path d="m-23.6-0.895c-9.95-2.99-23.5 9.22-16.5 17.3 4.59 5.37 20.6 2.77 25.8-13.4-6.1 11.2-17.6 12.8-22 9.61-5.15-3.76 1.25-14.3 12.7-13.5" fill="#239646" style="stroke-width:.433"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-5{fill:#34495e;}
|
||||
.cls-6{fill:none;stroke-linecap:round;}
|
||||
.cls-5,.cls-6{stroke-linejoin:round;stroke:#34495e;}
|
||||
</style>
|
||||
</defs>
|
||||
<polygon class="cls-5" transform="translate(8)" points="45.4 31.6 42.8 29.6 42.8 33.6"/>
|
||||
<line class="cls-6" x1="51.2" x2="41.4" y1="31.5" y2="31.5"/>
|
||||
<g transform="translate(51.6 26.3)">
|
||||
<path d="m-23.3 3.39c0.389-1.95-5.19-2.77-8.39 1.17-3.59 4.41 3.63 9.04 11.9 2.86 5.24-3.98 6.92-9.43 3.85-12.2-5.97-5.45-20.4-0.389-25.3 10.4 4.85-8.18 17-12 21.8-7.05 2.03 2.08 0.909 6.27-2.81 8.05-6.01 2.81-5.45-3.33-1.08-3.25" fill="#1b324f" style="stroke-width:.433"/>
|
||||
<path d="m-23.6-0.895c-9.95-2.99-23.5 9.22-16.5 17.3 4.59 5.37 20.6 2.77 25.8-13.4-6.1 11.2-17.6 12.8-22 9.61-5.15-3.76 1.25-14.3 12.7-13.5" fill="#239646" style="stroke-width:.433"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 965 B |
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style>
|
||||
.lights { fill:#fff }
|
||||
.other-worker > rect { stroke-width:0.5; fill:#addff3; stroke: #2980b9; }
|
||||
.other-worker .squares, .other-worker .side-handles { fill: #2980b9; }
|
||||
.selected-worker > rect { stroke-width:0.5; fill:#f0ecb6; stroke: #c18f35; }
|
||||
.selected-worker .squares, .selected-worker .side-handles { fill: #c18f35; }
|
||||
</style></defs>
|
||||
<g class="other-worker" transform="matrix(1.2 0 0 1.25 -7.14 -1.2)"><rect x="12.3" y="11.9" width="39.8" height="8.41" ry=".942"/><path class="squares" d="m19.2 13.4h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm-9.16 3.07h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27z"/><path class="side-handles" d="m14.1 13h1.24v6.1h-1.24zm34.5 0h1.24v6.1h-1.24z"/><g class="lights"><rect x="35.3" y="13.9" width="1.83" height="1.83" ry=".6"/><rect x="38.1" y="13.9" width="1.83" height="1.83" ry=".6"/><rect x="41" y="13.9" width="1.83" height="1.83" ry=".6"/></g></g>
|
||||
<g class="other-worker" transform="matrix(1.2 0 0 1.25 -7.14 24.7)"><rect x="12.3" y="11.9" width="39.8" height="8.41" ry=".942"/><path class="squares" d="m19.2 13.4h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm-9.16 3.07h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27z"/><path class="side-handles" d="m14.1 13h1.24v6.1h-1.24zm34.5 0h1.24v6.1h-1.24z"/><g class="lights"><rect x="35.3" y="13.9" width="1.83" height="1.83" ry=".6"/><rect x="38.1" y="13.9" width="1.83" height="1.83" ry=".6"/><rect x="41" y="13.9" width="1.83" height="1.83" ry=".6"/></g></g>
|
||||
<g class="selected-worker" transform="matrix(1.2 0 0 1.25 -6.84 11.7)"><rect x="12.3" y="11.9" width="39.8" height="8.41" ry=".942"/><path class="squares" d="m19.2 13.4h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm-9.16 3.07h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27zm3.05 0h2.27v2.27h-2.27z"/><path class="side-handles" d="m14.1 13h1.24v6.1h-1.24zm34.5 0h1.24v6.1h-1.24z"/><g class="lights"><rect x="35.3" y="13.9" width="1.83" height="1.83" ry=".6"/><rect x="38.1" y="13.9" width="1.83" height="1.83" ry=".6"/><rect x="41" y="13.9" width="1.83" height="1.83" ry=".6"/></g></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -41,10 +41,86 @@ const ImageMapper = {
|
|||
'image': 'ex_bmp_or.svg',
|
||||
'image_text': 'Bitmap OR',
|
||||
},
|
||||
'Citus Job': function(data) {
|
||||
// A 'Citus Job' represents a distributed query operation.
|
||||
// The details of the distributed operation are in the sub-plans,
|
||||
// but this node contains task count information, showing how many shards
|
||||
// the query is being distributed to.
|
||||
|
||||
const taskCount = data['Task Count'];
|
||||
const tasksShown = data['Tasks Shown'];
|
||||
|
||||
// "Task Count" is the number of shard operations being run.
|
||||
// "Tasks Shown" is either "All" or "One of N" depending on whether the returned query plan
|
||||
// contains one sample task or all of them.
|
||||
|
||||
// We show single-shard or multi-shard with different images, and we show the
|
||||
// literal value of 'Tasks Shown' as the image text.
|
||||
|
||||
const image = (taskCount === 1)
|
||||
? 'ex_citus_distributed_one_of_one.svg'
|
||||
: 'ex_citus_distributed_one_of_many.svg';
|
||||
|
||||
return {
|
||||
'image': image,
|
||||
'image_text': tasksShown
|
||||
};
|
||||
},
|
||||
'Citus Task': function(data) {
|
||||
// A 'Citus Task' represents a Task executed on a particular worker node.
|
||||
// The details of the Task are in the sub-plans, so for this node we just show
|
||||
// some details of the worker node.
|
||||
|
||||
const node = data['Node'];
|
||||
// "Node" has a value like "host=citus-worker-7 port=8394 dbname=postgres"
|
||||
// That's a bit long to display, so we shrink it to 'citus-worker-7:8394 postgres'
|
||||
const hostMatch = node.match(/host=(\S+)/);
|
||||
const portMatch = node.match(/port=(\S+)/);
|
||||
const dbnameMatch = node.match(/dbname=(\S+)/);
|
||||
|
||||
const host = hostMatch ? hostMatch[1] : '';
|
||||
let port = portMatch ? portMatch[1] : '';
|
||||
if (port === '5432') {
|
||||
// Default port. Don't bother showing.
|
||||
port = '';
|
||||
}
|
||||
const dbname = dbnameMatch ? dbnameMatch[1] : '';
|
||||
|
||||
let imageText = `Task ${host}`;
|
||||
if (port) {
|
||||
imageText += `:${port}`;
|
||||
}
|
||||
if (dbname) {
|
||||
imageText += ` ${dbname}`;
|
||||
}
|
||||
return {
|
||||
'image': 'ex_citus_worker_task.svg',
|
||||
'image_text': imageText
|
||||
};
|
||||
},
|
||||
'CTE Scan': {
|
||||
'image': 'ex_cte_scan.svg',
|
||||
'image_text': 'CTE Scan',
|
||||
},
|
||||
'Custom Scan': function(data) {
|
||||
const customPlanProvider = data['Custom Plan Provider'];
|
||||
|
||||
let image;
|
||||
|
||||
switch (customPlanProvider) {
|
||||
case 'Citus Adaptive':
|
||||
image = 'ex_citus.svg';
|
||||
break;
|
||||
default:
|
||||
image = 'ex_unknown.svg';
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
'image': image,
|
||||
'image_text': data['Custom Plan Provider']
|
||||
};
|
||||
},
|
||||
'Function Scan': {
|
||||
'image': 'ex_result.svg',
|
||||
'image_text': 'Function Scan',
|
||||
|
|
|
|||
|
|
@ -350,6 +350,46 @@ function parsePlan(data, ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
const citusDistributedQuery = data['Distributed Query'];
|
||||
if (citusDistributedQuery) {
|
||||
// This is a Citus Distributed Query plan.
|
||||
// It contains a 'Job' with one or more 'Tasks' in it.
|
||||
// We'll convert those Tasks into sub-Plans of this main plan and process it
|
||||
// with the regular Plan layout code.
|
||||
delete data['Distributed Query'];
|
||||
|
||||
// Convert the Job into a 'Citus Job' sub-plan.
|
||||
// That allows us to show details of the Task count etc.
|
||||
const citusJob = citusDistributedQuery['Job'];
|
||||
const jobPlan = {
|
||||
'Node Type': 'Citus Job',
|
||||
...citusJob
|
||||
};
|
||||
data['Plans'] = [jobPlan];
|
||||
|
||||
// Convert each of the Tasks into 'Citus Task' sub-plans of the Job plan.
|
||||
const citusTasks = jobPlan['Tasks'];
|
||||
if (citusTasks) {
|
||||
delete jobPlan['Tasks'];
|
||||
|
||||
const citusTaskPlans = citusTasks.map(citusJobTask => {
|
||||
const taskPlan = {
|
||||
'Node Type': 'Citus Task',
|
||||
...citusJobTask
|
||||
};
|
||||
|
||||
// A Citus Task contains a 'Remote Plan' which is the actual plan
|
||||
// executed on the worker nodes. It's actually an array of arrays.
|
||||
const remotePlan = taskPlan['Remote Plan'];
|
||||
delete taskPlan['Remote Plan'];
|
||||
// A Remote Plan is an array of arrays of Plans.
|
||||
taskPlan['Plans'] = remotePlan.flatMap(arr => arr.map(planLevel1Entry => planLevel1Entry['Plan']));
|
||||
return taskPlan;
|
||||
});
|
||||
jobPlan['Plans'] = citusTaskPlans;
|
||||
}
|
||||
}
|
||||
|
||||
// Start calculating xpos, ypos, width and height for child plans if any
|
||||
if ('Plans' in data) {
|
||||
data['width'] += offsetX;
|
||||
|
|
|
|||
Loading…
Reference in New Issue