mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 10:10:19 -06:00
Fixes # 4778 - Implement the query plan analyzer
Look 'n' Feel and implementation logic are inspired from 'http://explain.depsez.com'. It now creates three tabs under the 'Explain' panel when executing a query using the Explain Analyze/Explain button from the toolbar of the Query tool. Graphical --------- -> Graphical Explain Plan Analysis -------- -> Table to show details of the explain plan analyse. -> Each row represents the statistics per Explain Plan Node -> It may contains columns like node information, exclusive timing (time spent for this explain node excluding the child nodes), inclusive timing, actual rows, plan rows, rowsx (misestimation between planned vs actual rows), loop. -> Background color of exclusive, inclusive, rows changes based on their values. i.e. If Percentage of exclusive, and inclusive timings of total query time is: > 90 - Red Color > 50 - Orange (Between Red & Yellow Color) > 10 - Yellow color If planner misestimation for the rows is > 1000 times - Red Color > 100 times - Orange (Between Red & Yellow Color) > 10 times - Yellow Color Also - if actual rows <= planned rows then it shows up arrow, else it shows down arrow. Statistics ---------- -> It contains a HTML table for the statistics per Node Type, and a HTML table for the statistics per table. Reviewed by: Akshay Joshi
This commit is contained in:
parent
1e4fd552ac
commit
6e4923d762
BIN
docs/en_US/images/query_explain_analyze_statistics.png
Normal file
BIN
docs/en_US/images/query_explain_analyze_statistics.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 250 KiB |
BIN
docs/en_US/images/query_explain_analyze_table.png
Normal file
BIN
docs/en_US/images/query_explain_analyze_table.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 KiB |
Binary file not shown.
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 166 KiB |
BIN
docs/en_US/images/query_output_explain_options.png
Normal file
BIN
docs/en_US/images/query_output_explain_options.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
docs/en_US/images/query_toolbar_explain.png
Normal file
BIN
docs/en_US/images/query_toolbar_explain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 79 KiB |
@ -16,8 +16,8 @@ allows you to:
|
||||
:ref:`updatable <updatable-result-set>`.
|
||||
* Displays current connection and transaction status as configured by the user.
|
||||
* Save the data displayed in the output panel to a CSV file.
|
||||
* Review the execution plan of a SQL statement in either a text or a graphical
|
||||
format.
|
||||
* Review the execution plan of a SQL statement in either a text, a graphical
|
||||
format or a table format (similar to https://explain.depesz.com).
|
||||
* View analytical information about a SQL statement.
|
||||
|
||||
|
||||
@ -166,20 +166,31 @@ All rowsets from previous queries or commands that are displayed in the *Data
|
||||
Output* panel will be discarded when you invoke another query; open another
|
||||
Query Tool tab to keep your previous results available.
|
||||
|
||||
Use the *Explain* tab to view a graphical representation of a query:
|
||||
Explain Panel
|
||||
*************
|
||||
|
||||
.. image:: images/query_output_explain.png
|
||||
:alt: Query tool explain panel
|
||||
To generate the *Explain* or *Explain Analyze* plan of a query, click on
|
||||
*Explain* or *Explain Analyze* button in the toolbar.
|
||||
|
||||
More options related to *Explain* and *Explain Analyze* can be selected from
|
||||
the drop down on the right side of *Explain Analyze* button in the toolbar.
|
||||
|
||||
.. image:: images/query_toolbar_explain.png
|
||||
:alt: Query tool toolbar explain button
|
||||
:align: center
|
||||
|
||||
To generate a graphical explain diagram, open the *Explain* tab, and select
|
||||
*Explain*, *Explain Analyze*, or one or more options from the *Explain options*
|
||||
drop-down. Please note that *EXPLAIN VERBOSE*
|
||||
cannot be displayed graphically. Hover over an icon on the *Explain* tab to
|
||||
review information about that item; a popup window will display information
|
||||
about the selected object. For information on JIT statistics, triggers and a
|
||||
summary, hover over the icon on top-right corner; a similar popup window will
|
||||
be displayed when appropriate.
|
||||
Please note that pgAdmin generates the *Explain [Analyze]* plan in JSON format.
|
||||
|
||||
On successful generation of *Explain* plan, it will create three tabs/panels
|
||||
under the Explain panel.
|
||||
|
||||
* Graphical
|
||||
|
||||
Please note that *EXPLAIN VERBOSE* cannot be displayed graphically. Hover over
|
||||
an icon on the *Graphical* tab to review information about that item; a popup
|
||||
window will display information about the selected object. For information on
|
||||
JIT statistics, triggers and a summary, hover over the icon on top-right
|
||||
corner; a similar popup window will be displayed when appropriate.
|
||||
|
||||
Use the download button on top left corner of the *Explain* canvas to download
|
||||
the plan as an SVG file.
|
||||
@ -193,6 +204,44 @@ the plan as an SVG file.
|
||||
Note that the query plan that accompanies the *Explain analyze* is available on
|
||||
the *Data Output* tab.
|
||||
|
||||
* Table
|
||||
|
||||
*Table* tab shows the plan details in table format, it generates table format
|
||||
similar to *explain.depsez.com*. Each row of the table represent the data for a
|
||||
*Explain Plan Node*. It may contain the node information, exclusive timing,
|
||||
inclusive timing, actual vs planned rows differences, actual rows, planned
|
||||
rows, loops.
|
||||
|
||||
background color of the exclusive, inclusive, and Rows X columns may vary based on the
|
||||
difference between actual vs planned.
|
||||
|
||||
If percentage of the exclusive/inclusive timings of the total query time is:
|
||||
> 90 - Red color
|
||||
> 50 - Orange (between red and yellow) color
|
||||
> 10 - Yellow color
|
||||
|
||||
If planner mis-estimated number of rows (actual vs planned) by
|
||||
10 times - Yellow color
|
||||
100 times - Orange (between Red and Yellow) color
|
||||
1000 times - Red color
|
||||
|
||||
.. image:: images/query_explain_analyze_table.png
|
||||
:alt: Query tool explain plan table
|
||||
:align: center
|
||||
|
||||
* Statistics
|
||||
|
||||
*Statistics* tab shows two tables:
|
||||
1. Statistics per Plan Node Type
|
||||
2. Statistics per Table
|
||||
|
||||
.. image:: images/query_explain_analyze_statistics.png
|
||||
:alt: Query tool explain plan statistics
|
||||
:align: center
|
||||
|
||||
Messages Panel
|
||||
**************
|
||||
|
||||
Use the *Messages* tab to view information about the most recently executed
|
||||
query:
|
||||
|
||||
@ -209,6 +258,9 @@ query took to complete and how many rows were retrieved:
|
||||
:alt: Query tool output information
|
||||
:align: center
|
||||
|
||||
Query History Panel
|
||||
*******************
|
||||
|
||||
Use the *Query History* tab to review activity for the current session:
|
||||
|
||||
.. image:: images/query_output_history.png
|
||||
@ -237,6 +289,9 @@ retained. By default, the last 20 queries are stored for each database. This
|
||||
can be adjusted in `config_local.py` by overriding the `MAX_QUERY_HIST_STORED`
|
||||
value. See the :ref:`Deployment <deployment>` section for more information.
|
||||
|
||||
Connection Status
|
||||
*****************
|
||||
|
||||
Use the *Connection status* feature to view the current connection and
|
||||
transaction status by clicking on the status icon in the Query Tool:
|
||||
|
||||
|
@ -10,6 +10,7 @@ New features
|
||||
************
|
||||
|
||||
| `Issue #3009 <https://redmine.postgresql.org/issues/3009>`_ - Added Copy with headers functionality when copy data from Query Tool/View Data.
|
||||
| `Issue #4778 <https://redmine.postgresql.org/issues/4778>`_ - Implemeted the Query Plan Analyser.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
@ -31,4 +32,4 @@ Bug fixes
|
||||
| `Issue #4768 <https://redmine.postgresql.org/issues/4768>`_ - Ensure pgAdmin should work behind reverse proxy on a non standard port.
|
||||
| `Issue #4769 <https://redmine.postgresql.org/issues/4769>`_ - Fix query tool open issue on Internet Explorer.
|
||||
| `Issue #4777 <https://redmine.postgresql.org/issues/4777>`_ - Fix issue where query history is not visible in the query history tab.
|
||||
| `Issue #4780 <https://redmine.postgresql.org/issues/4780>`_ - Ensure the search path should not be quoted for Function, Procedure and Trigger Function.
|
||||
| `Issue #4780 <https://redmine.postgresql.org/issues/4780>`_ - Ensure the search path should not be quoted for Function, Procedure and Trigger Function.
|
||||
|
@ -1,39 +1,3 @@
|
||||
.pg-explain-zoom-area {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pg-explain-zoom-btn,
|
||||
.pg-explain-download-btn {
|
||||
top: 5px;
|
||||
min-width: 25px;
|
||||
cursor: pointer;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.pg-explain-zoom-area:hover,
|
||||
.pg-explain-stats-area:hover,
|
||||
.pg-explain-download-area:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.pg-explain-stats-area {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 25px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.pg-explain-stats-btn {
|
||||
top: 5px;
|
||||
min-width: 25px;
|
||||
pointer-events: none;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.explain-tooltip {
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
@ -49,7 +13,6 @@ td.explain-tooltip-val {
|
||||
padding: 2px !important;
|
||||
font-size: small;
|
||||
font-weight: normal;
|
||||
|
||||
}
|
||||
|
||||
.pgadmin-tooltip-table {
|
||||
@ -58,16 +21,3 @@ td.explain-tooltip-val {
|
||||
top: auto;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.pgadmin-explain-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.pg-explain-download-area {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 79px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,143 @@
|
||||
.pgadmin-explain-tooltip {
|
||||
position: absolute;
|
||||
opacity:0;
|
||||
opacity: 0;
|
||||
color: $color-gray-lighter;
|
||||
background-color: $color-gray-dark;
|
||||
}
|
||||
|
||||
$explain-bg-color-2: #FFEE88;
|
||||
$explain-bg-color-3: #EE8800;
|
||||
$explain-bg-color-4: #880000;
|
||||
$explain-fg-color-3: #FFFFFF;
|
||||
$explain-fg-color-4: #FFFFFF;
|
||||
|
||||
.sql-editor-explain {
|
||||
.backform-tab {
|
||||
.tab-content {
|
||||
bottom: 0.5rem;
|
||||
background-color: $color-bg;
|
||||
|
||||
div[data-explain-tabpanel=graphical] {
|
||||
.btn-group {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
margin-left: 4px;
|
||||
opacity: 0.5;
|
||||
|
||||
&.pg-explain-download-area.btn-group {
|
||||
left: 85px;
|
||||
}
|
||||
|
||||
&.pg-explain-stats-area {
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
*:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.tab-pane[data-explain-tabpanel=table] {
|
||||
|
||||
border-bottom: $panel-border;
|
||||
|
||||
.pga-ex-exclusive-1,
|
||||
.pga-ex-inclusive-1,
|
||||
.pga-ex-rowsx-1 {}
|
||||
|
||||
td.pga-ex-exclusive-2,
|
||||
td.pga-ex-inclusive-2,
|
||||
td.pga-ex-rowsx-2 {
|
||||
background-color: $explain-bg-color-2;
|
||||
}
|
||||
|
||||
td.pga-ex-exclusive-3,
|
||||
td.pga-ex-inclusive-3,
|
||||
td.pga-ex-rowsx-3 {
|
||||
background-color: $explain-bg-color-3;
|
||||
color: $explain-fg-color-3;
|
||||
}
|
||||
|
||||
td.pga-ex-exclusive-4,
|
||||
td.pga-ex-inclusive-4,
|
||||
td.pga-ex-rowsx-4 {
|
||||
background-color: $explain-bg-color-4;
|
||||
color: $explain-fg-color-4;
|
||||
}
|
||||
|
||||
.pg-ex-subplans {
|
||||
position: absolute;
|
||||
margin-left: -20px;
|
||||
margin-top: 3px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table {
|
||||
tr {
|
||||
&[data-collapsed=true] {
|
||||
td {
|
||||
border-bottom: $table-hover-border;
|
||||
border-bottom-style: dotted !important;
|
||||
border-bottom-width: medium !important;
|
||||
}
|
||||
}
|
||||
td {
|
||||
li {
|
||||
font-size: small;
|
||||
opacity: 0.75;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-all;
|
||||
overflow: visible;
|
||||
white-space: -moz-pre-wrap !important;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
white-space: -webkit-pre-wrap;
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
&.pg-ex-highlighter {
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
&.pga-ex-collapsible {
|
||||
td {
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.tab-pane[data-explain-tabpanel=statistics] {
|
||||
.badge {
|
||||
cursor: initial;
|
||||
}
|
||||
table[for=per_table] {
|
||||
tr {
|
||||
&.table {
|
||||
background-color: $color-gray-lighter;
|
||||
|
||||
td:first-child {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
}
|
||||
&.node {
|
||||
td.name {
|
||||
padding-left: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,5 +115,51 @@ define([], function() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decimal adjustment of a number.
|
||||
*
|
||||
* @param {String} type The type of adjustment.
|
||||
* @param {Number} value The number.
|
||||
* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
|
||||
* @returns {Number} The adjusted value.
|
||||
*/
|
||||
function decimalAdjust(type, value, exp) {
|
||||
// If the exp is undefined or zero...
|
||||
if (typeof exp === 'undefined' || +exp === 0) {
|
||||
return Math[type](value);
|
||||
}
|
||||
value = +value;
|
||||
exp = +exp;
|
||||
// If the value is not a number or the exp is not an integer...
|
||||
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
|
||||
return NaN;
|
||||
}
|
||||
// Shift
|
||||
value = value.toString().split('e');
|
||||
value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
|
||||
// Shift back
|
||||
value = value.toString().split('e');
|
||||
return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
|
||||
}
|
||||
|
||||
// Decimal round
|
||||
if (!Math.round10) {
|
||||
Math.round10 = function(value, exp) {
|
||||
return decimalAdjust('round', value, exp);
|
||||
};
|
||||
}
|
||||
// Decimal floor
|
||||
if (!Math.floor10) {
|
||||
Math.floor10 = function(value, exp) {
|
||||
return decimalAdjust('floor', value, exp);
|
||||
};
|
||||
}
|
||||
// Decimal ceil
|
||||
if (!Math.ceil10) {
|
||||
Math.ceil10 = function(value, exp) {
|
||||
return decimalAdjust('ceil', value, exp);
|
||||
};
|
||||
}
|
||||
|
||||
return pgAdmin;
|
||||
});
|
||||
|
@ -373,6 +373,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
.obj_properties {
|
||||
.btn-group {
|
||||
.btn {
|
||||
@extend .rounded;
|
||||
:not(:first-child) {
|
||||
@extend .rounded-left;
|
||||
}
|
||||
:not(:last-child) {
|
||||
@extend .rounded-right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.obj_properties .badge .caret {
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
|
Loading…
Reference in New Issue
Block a user