1
0
mirror of https://gitlab.com/depesz/explain.depesz.com.git synced 2025-07-05 00:58:52 +02:00

Added stats

In view of query, added 3rd tab (HTML, TEXT) - STATS.

This shows list of all different node types with their repetition count,
summarized time, and percent of total query time, plus similar per table
stats.
This commit is contained in:
Hubert depesz Lubaczewski
2011-07-13 02:29:41 +02:00
parent a5fc1f2544
commit b239a3b5ca
4 changed files with 122 additions and 5 deletions

View File

@ -111,9 +111,34 @@ sub show {
return $self->redirect_to( 'new-explain' );
}
# Get stats from plan
my $stats = { 'tables' => {} };
my @elements = ( $explain->top_node );
while ( my $e = shift @elements ) {
push @elements, values ${ $e->ctes } if $e->{ 'ctes' };
push @elements, @{ $e->sub_nodes } if $e->sub_nodes;
push @elements, @{ $e->initplans } if $e->initplans;
push @elements, @{ $e->subplans } if $e->subplans;
$stats->{'nodes'}->{ $e->type }->{'count'}++;
$stats->{'nodes'}->{ $e->type }->{'time'}+=$e->total_exclusive_time if $e->total_exclusive_time;
next unless $e->scan_on;
next unless $e->scan_on->{ 'table_name' };
$stats->{ 'tables' }->{ $e->scan_on->{ 'table_name' } } ||= {};
my $S = $stats->{ 'tables' }->{ $e->scan_on->{ 'table_name' } };
$S->{ $e->{ 'type' } }->{ 'count' }++;
$S->{ ':total' }->{ 'count' }++;
if ( defined( my $t = $e->total_exclusive_time ) ) {
$S->{ $e->type }->{ 'time' } += $t;
$S->{ ':total' }->{ 'time' } += $t;
}
}
# put explain and title to stash
$self->stash->{ explain } = $explain;
$self->stash->{ title } = $title;
$self->stash->{ stats } = $stats;
# render will be called automatically
return;

View File

@ -206,7 +206,7 @@ div.explain-form a:hover {background:#e5ecf9}
*:first-child+html #explain-form input {border:0}
.result {margin:0;padding:0}
.result-text, .result-html {margin:0;padding:0;border:1px solid #ccc;overflow:auto}
.result-text, .result-html, .result-stats {margin:0;padding:0;border:1px solid #ccc;overflow:auto}
.result-text {background:#222 url('../img/code-bg.gif');color:#fff}
.result-text pre {margin:0;padding:1em}
@ -222,7 +222,7 @@ div.explain-form a:hover {background:#e5ecf9}
border-radius:4px 0px 0px 0px
}
.result .tabs .text a {
.result .tabs .stats a {
-moz-border-radius:0px 4px 0px 0px;
border-radius:0px 4px 0px 0px
}
@ -363,3 +363,18 @@ div.message p.hint { color: #ff0; padding: 0; margin: 0; }
div.message p.hint a { color: #ff0; }
div.message p.hint a:hover { color: #ff0; }
div.plea { text-align: center; color: #666; padding-top: 1em; }
.result-stats h1 {color:#123}
.result-stats table {margin:5px;border-collapse:collapse}
.result-stats table th,
.result-stats table td {padding:4px 8px;border:1px solid #ccc;background:#fff;text-align:left;vertical-align:top}
.result-stats table th {background:#234;text-align:center;color:#fff}
.result-stats table td.count,
.result-stats table td.time,
.result-stats table td.percent { text-align: right }
.result-stats table td.table-name { font-weight: bold; }
.result-stats table td.scan-type { padding-left: 2em; }
.result-stats table tr.table-summary td { background: #e5ecf9 }

View File

@ -197,11 +197,20 @@
if ( 'text' == view.toLowerCase( ) ) {
result.find( 'div.result-html' ).hide( );
result.find( 'div.result-stats' ).hide( );
result.find( 'div.result-text' ).show( );
return;
}
if ( 'html' == view.toLowerCase( ) ) {
result.find( 'div.result-html' ).show( );
result.find( 'div.result-stats' ).hide( );
result.find( 'div.result-text' ).hide( );
return;
}
result.find( 'div.result-html' ).hide( );
result.find( 'div.result-stats' ).show( );
result.find( 'div.result-text' ).hide( );
},

View File

@ -50,7 +50,7 @@
% my $exclusive_point = 1;
% my $inclusive_point = 1;
%
% if ( $explain->top_node->total_inclusive_time && $node->total_exclusive_time ne '' && $node->total_inclusive_time ne '' ) {
% if ( $explain->top_node->total_inclusive_time && defined( $node->total_exclusive_time ) && defined( $node->total_inclusive_time ) && $node->total_exclusive_time ne '' && $node->total_inclusive_time ne '' ) {
%
% $exclusive_point = $node->total_exclusive_time / $explain->top_node->total_inclusive_time;
%
@ -156,6 +156,9 @@
% elsif ( 'Index Scan' eq $node->type ) {
using <%= $node->scan_on->{ index_name } %> on <%= $node->scan_on->{ table_name } %> <%= $node->scan_on->{ table_alias } || '' %>
% }
% elsif ( 'Index Scan Backward' eq $node->type ) {
using <%= $node->scan_on->{ index_name } %> on <%= $node->scan_on->{ table_name } %> <%= $node->scan_on->{ table_alias } || '' %>
% }
% elsif ( 'Seq Scan' eq $node->type ) {
on <%= $node->scan_on->{ table_name } %> <%= $node->scan_on->{ table_alias } || '' %>
% }
@ -349,6 +352,12 @@
onclick="$( this ).explain( 'toggleView', 'text', this ); return false;"
onkeypress="return this.onclick( );">TEXT</a>
</li>
<li class="stats">
<a href="#stats"
title="view plan stats"
onclick="$( this ).explain( 'toggleView', 'stats', this ); return false;"
onkeypress="return this.onclick( );">STATS</a>
</li>
</ul>
</div>
@ -395,6 +404,65 @@
<pre id="source"><%= $explain->source =%></pre>
</div>
<div class="result-stats hidden">
<h1>Per node type stats</h1>
<table class="stats">
<thead>
<tr><th>scan type</th><th>count</th><th>sum of times</th><th>% of query</th></tr>
</thead>
<tbody>
% for my $node_type ( sort keys %{ $stats->{'nodes'} } ) {
<tr class="table-detail">
<td class="node-type"><%= $node_type %></td>
<td class="count"><%= $stats->{'nodes'}->{$node_type}->{'count'} %></td>
<td class="time"><%= sprintf '%.03f ms', $stats->{'nodes'}->{$node_type}->{'time'} || 0 %></td>
<td class="percent">
<% my $total = $explain->top_node->total_inclusive_time || 0; %>
<% my $current = $stats->{'nodes'}->{$node_type}->{'time'} || 0; %>
<% my $percent = $total == 0 ? 0 : 100 * $current / $total; %>
<%= sprintf '%.1f %%', $percent %>
</td>
</tr>
% }
</tbody>
</table>
<h1>Per table stats</h1>
<table class="stats">
<thead>
<tr><th>Table name</th><th>Scan count</th><th>Total time</th><th>% of query</th></tr>
<tr><th>scan type</th><th>count</th><th>sum of times</th><th>% of table</th></tr>
</thead>
<tbody>
% for my $table_name ( sort keys %{ $stats->{'tables'} } ) {
<tr class="table-summary">
<td class="table-name"><%= $table_name %></td>
<td class="count"><%= $stats->{'tables'}->{$table_name}->{':total'}->{'count'} %></td>
<td class="time"><%= sprintf '%.03f ms', $stats->{'tables'}->{$table_name}->{':total'}->{'time'} || 0 %></td>
<td class="percent">
<% my $total = $explain->top_node->total_inclusive_time || 0; %>
<% my $current = $stats->{'tables'}->{$table_name}->{':total'}->{'time'} || 0; %>
<% my $percent = $total == 0 ? 0 : 100 * $current / $total; %>
<%= sprintf '%.1f %%', $percent %>
</td>
</tr>
% for my $scan_type ( sort grep { ! /^:/ } keys %{ $stats->{'tables'}->{$table_name} } ) {
<tr class="table-detail">
<td class="scan-type"><%= $scan_type %></td>
<td class="count"><%= $stats->{'tables'}->{$table_name}->{$scan_type}->{'count'} %></td>
<td class="time"><%= sprintf '%.03f ms', $stats->{'tables'}->{$table_name}->{$scan_type}->{'time'} || 0 %></td>
<td class="percent">
<% my $total = $stats->{'tables'}->{$table_name}->{':total'}->{'time'} || 0; %>
<% my $current = $stats->{'tables'}->{$table_name}->{$scan_type}->{'time'} || 0; %>
<% my $percent = $total == 0 ? 0 : 100 * $current / $total; %>
<%= sprintf '%.1f %%', $percent %>
</td>
</tr>
% }
% }
</tbody>
</table>
</div>
<div class="plea">
Did it help you? Perhaps you can <a href="http://www.depesz.com/index.php/can-you-help-me/">help me</a>.
</div>