File Coverage

blib/lib/DBIx/Class/QueryLog/Analyzer.pm
Criterion Covered Total %
statement 48 49 97.9
branch 1 2 50.0
condition n/a
subroutine 7 7 100.0
pod 5 5 100.0
total 61 63 96.8


line stmt bran cond sub pod time code
1             package DBIx::Class::QueryLog::Analyzer;
2             $DBIx::Class::QueryLog::Analyzer::VERSION = '1.005001';
3             # ABSTRACT: Query Analysis
4              
5 3     3   1171 use Moo;
  3         7  
  3         15  
6 3     3   787 use Types::Standard 'InstanceOf';
  3         5  
  3         19  
7              
8             has querylog => (
9             is => 'rw',
10             isa => InstanceOf['DBIx::Class::QueryLog']
11             );
12              
13              
14             sub get_sorted_queries {
15 1     1 1 1825 my ($self) = @_;
16              
17 1         3 my @queries;
18              
19 1         1 foreach my $l (@{ $self->querylog->log }) {
  1         20  
20 2         22 push(@queries, @{ $l->get_sorted_queries });
  2         7  
21             }
22 1         23 return [ reverse sort { $a->time_elapsed <=> $b->time_elapsed } @queries ];
  3         38  
23             }
24              
25             sub get_fastest_query_executions {
26 3     3 1 525 my ($self, $sql) = @_;
27              
28 3         3 my @queries;
29 3         4 foreach my $l (@{ $self->querylog->log }) {
  3         56  
30 12         70 push(@queries, @{ $l->get_sorted_queries($sql) });
  12         28  
31             }
32              
33 3         11 return [ sort { $a->time_elapsed <=> $b->time_elapsed } @queries ];
  6         76  
34             }
35              
36              
37             sub get_slowest_query_executions {
38 2     2 1 3107 my ($self, $sql) = @_;
39              
40 2         4 return [ reverse @{ $self->get_fastest_query_executions($sql) } ];
  2         5  
41             }
42              
43              
44             sub get_totaled_queries {
45 2     2 1 468 my ($self, $honor_buckets) = @_;
46              
47 2         3 my %totaled;
48 2         3 foreach my $l (@{ $self->querylog->log }) {
  2         33  
49 4         49 foreach my $q (@{ $l->queries }) {
  4         31  
50 6 50       24 if($honor_buckets) {
51 0         0 return $self->get_totaled_queries_by_bucket;
52             } else {
53 6         73 $totaled{$q->sql}->{count}++;
54 6         126 $totaled{$q->sql}->{time_elapsed} += $q->time_elapsed;
55 6         105 push(@{ $totaled{$q->sql}->{queries} }, $q);
  6         73  
56             }
57             }
58             }
59 2         17 return \%totaled;
60             }
61              
62              
63             sub get_totaled_queries_by_bucket {
64 1     1 1 2485 my ($self) = @_;
65              
66 1         2 my %totaled;
67 1         2 foreach my $l (@{ $self->querylog->log }) {
  1         16  
68 2         42 foreach my $q (@{ $l->queries }) {
  2         16  
69 2         28 $totaled{$q->bucket}->{$q->sql}->{count}++;
70 2         63 $totaled{$q->bucket}->{$q->sql}->{time_elapsed} += $q->time_elapsed;
71 2         39 push(@{ $totaled{$q->bucket}->{$q->sql}->{queries} }, $q);
  2         24  
72             }
73             }
74 1         19 return \%totaled;
75             }
76              
77             1;
78              
79             __END__
80              
81             =pod
82              
83             =encoding UTF-8
84              
85             =head1 NAME
86              
87             DBIx::Class::QueryLog::Analyzer - Query Analysis
88              
89             =head1 VERSION
90              
91             version 1.005001
92              
93             =head1 SYNOPSIS
94              
95             Analyzes the results of a QueryLog. Create an Analyzer and pass it the
96             QueryLog:
97              
98             my $schema = ... # Get your schema!
99             my $ql = DBIx::Class::QueryLog->new;
100             $schema->storage->debugobj($ql);
101             $schema->storage->debug(1);
102             ... # do some stuff!
103             my $ana = DBIx::Class::QueryLog::Analyzer->new({ querylog => $ql });
104             my @queries = $ana->get_sorted_queries;
105             # or...
106             my $totaled = $ana->get_totaled_queries;
107              
108             =head1 METHODS
109              
110             =head2 new
111              
112             Create a new DBIx::Class::QueryLog::Analyzer
113              
114             =head2 get_sorted_queries
115              
116             Returns an arrayref of all Query objects, sorted by elapsed time (descending).
117              
118             =head2 get_fastest_query_executions($sql_statement)
119              
120             Returns an arrayref of Query objects representing in order of the fastest
121             executions of a given statement. Accepts either SQL or a
122             DBIx::Class::QueryLog::Query object. If given SQL, it must match the executed
123             SQL, including placeholders.
124              
125             $ana->get_slowest_query_executions("SELECT foo FROM bar WHERE gorch = ?");
126              
127             =head2 get_slowest_query_executions($sql_statement)
128              
129             Opposite of I<get_fastest_query_executions>. Same arguments.
130              
131             =head2 get_totaled_queries
132              
133             Returns hashref of the queries executed, with same-SQL combined and totaled.
134             So if the same query is executed multiple times, it will be combined into
135             a single entry. The structure is:
136              
137             $var = {
138             'SQL that was EXECUTED' => {
139             count => 2,
140             time_elapsed => 1931,
141             queries => [
142             DBIx::Class::QueryLog...,
143             DBIx::Class::QueryLog...
144             ]
145             }
146             }
147              
148             This is useful for when you've fine-tuned individually slow queries and need
149             to isolate which queries are executed a lot, so that you can determine which
150             to focus on next.
151              
152             To sort it you'll want to use something like this (sorry for the long line,
153             blame perl...):
154              
155             my $analyzed = $ana->get_totaled_queries;
156             my @keys = reverse sort {
157             $analyzed->{$a}->{'time_elapsed'} <=> $analyzed->{$b}->{'time_elapsed'}
158             } keys(%{ $analyzed });
159              
160             So one could sort by count or time_elapsed.
161              
162             =head2 get_totaled_queries_by_bucket
163              
164             Same as get_totaled_queries, but breaks the totaled queries up by bucket:
165              
166             $var = {
167             'bucket1' => {
168             'SQL that was EXECUTED' => {
169             count => 2,
170             time_elapsed => 1931,
171             queries => [
172             DBIx::Class::QueryLog...,
173             DBIx::Class::QueryLog...
174             ]
175             }
176             }
177             'bucket2' => { ... }
178             }
179              
180             It is otherwise identical to get_totaled_queries
181              
182             =head1 AUTHORS
183              
184             =over 4
185              
186             =item *
187              
188             Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>
189              
190             =item *
191              
192             Cory G Watson <gphat at cpan.org>
193              
194             =back
195              
196             =head1 COPYRIGHT AND LICENSE
197              
198             This software is copyright (c) 2015 by Cory G Watson <gphat at cpan.org>.
199              
200             This is free software; you can redistribute it and/or modify it under
201             the same terms as the Perl 5 programming language system itself.
202              
203             =cut