diff --git a/lib/Explain/Controller.pm b/lib/Explain/Controller.pm index 828a1cd..707b49d 100755 --- a/lib/Explain/Controller.pm +++ b/lib/Explain/Controller.pm @@ -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->{ title } = $title; + $self->stash->{ stats } = $stats; # render will be called automatically return; diff --git a/public/css/style.css b/public/css/style.css index 7eb58a9..7292b6e 100755 --- a/public/css/style.css +++ b/public/css/style.css @@ -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 } + diff --git a/public/js/explain.js b/public/js/explain.js index ea5e2c7..20da5da 100644 --- a/public/js/explain.js +++ b/public/js/explain.js @@ -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; } - result.find( 'div.result-html' ).show( ); + 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( ); }, diff --git a/templates/controller/show.html.ep b/templates/controller/show.html.ep index 7323bcb..74c84be 100755 --- a/templates/controller/show.html.ep +++ b/templates/controller/show.html.ep @@ -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 +
<%= $explain->source =%>+ +