home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / mysql / scripts / mysql_explain_log < prev    next >
Text File  |  2008-04-17  |  12KB  |  414 lines

  1. #!@PERL@
  2. # Copyright (C) 2001-2003, 2006 MySQL AB
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; version 2 of the License.
  6. # This program is distributed in the hope that it will be useful,
  7. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9. # GNU General Public License for more details.
  10. # You should have received a copy of the GNU General Public License
  11. # along with this program; if not, write to the Free Software
  12. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  13.  
  14. use strict;
  15. use warnings;
  16. use DBI;
  17.  
  18. use Getopt::Long;
  19. $Getopt::Long::ignorecase=0;
  20.  
  21. my $Param={};
  22.  
  23. $Param->{host}='';
  24. $Param->{user}='';
  25. $Param->{password}='';
  26. $Param->{PrintError}=0;
  27. $Param->{socket}='';
  28.  
  29. my $help;
  30.  
  31. if (!GetOptions (
  32.          'date|d:i' => \$Param->{ViewDate},
  33.          'host|h:s' => \$Param->{host},
  34.          'user|u:s' => \$Param->{user},
  35.          'password|p:s' => \$Param->{password},
  36.          'printerror|e:s' => \$Param->{PrintError},
  37.          'socket|s:s' => \$Param->{socket},
  38.          'help|h' => \$help,
  39.         )) {
  40.   ShowOptions();
  41.   exit(0);
  42. }
  43. if (defined ($help)) {
  44.   ShowOptions();
  45.   exit(0);
  46. }
  47.  
  48.   print "explain_log    provided by http://www.mobile.de\n";
  49.   print "===========    ================================\n";
  50.  
  51.   $Param->{UpdateCount} = 0;
  52.   $Param->{SelectCount} = 0;
  53.   $Param->{IdxUseCount} = 0;
  54.   $Param->{LineCount} = 0;
  55.  
  56.   $Param->{Init} = 0;
  57.   $Param->{Field} = 0;
  58.   $Param->{Refresh} = 0;
  59.   $Param->{QueryCount} = 0;
  60.   $Param->{Statistics} =0;
  61.  
  62.   $Param->{Query} = undef;
  63.   $Param->{ALL} = undef ;
  64.   $Param->{Comment} = undef ;
  65.  
  66.   @{$Param->{Rows}} = (qw|possible_keys key type|);
  67.  
  68.   if ($Param->{ViewDate}) {
  69.     $Param->{View} = 0;
  70.   }
  71.   else {
  72.     $Param->{View} = 1;
  73.   }
  74.  
  75.   #print "Date=$Param->{ViewDate}, host=$Param->{host}, user=$Param->{user}, password=$Param->{password}\n";
  76.  
  77.   $Param->{dbh}=DBI->connect("DBI:mysql:host=$Param->{host}".($Param->{socket}?";mysql_socket=$Param->{socket}":""),$Param->{user},$Param->{password},{PrintError=>0});
  78.   if (DBI::err()) {
  79.     print "Error: " . DBI::errstr() . "\n";
  80.   }
  81.   else {
  82.     $Param->{Start} = time;
  83.     while(<>) {
  84.       $Param->{LineCount} ++ ;
  85.  
  86.       if ($Param->{ViewDate} ) {
  87.     if (m/^(\d{6})\s+\d{1,2}:\d\d:\d\d\s.*$/) { # get date
  88.       #print "# $1 #\n";
  89.       if ($1 == $Param->{ViewDate}) {
  90.         $Param->{View} = 1;
  91.       }
  92.       else {
  93.         $Param->{View} = 0;
  94.       }
  95.     }
  96.       }
  97.       if ($Param->{View} ) {
  98.     #print "->>>$_";
  99.  
  100.     if (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
  101.       #print "C-$1--$2--$3------\n";
  102.       RunQuery($Param);
  103.       if (defined $3) {
  104.         $Param->{CID}->{$2} = $3 ;
  105.         #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
  106.       }
  107.     }
  108.  
  109.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Connect.+$/i) { # get connection ID($2) and database($3)
  110.       #print "\n <<<<<<<<<<<<<<<<<<----------------------------<<<<<<<<<<<<<<<< \n";
  111.       #print "Connect \n";
  112.       RunQuery($Param);
  113.     }
  114.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Change user .*\s+on\s+(.*)$/i) { # get connection ID($2) and database($3)
  115.       #print "C-$1--$2--$3------\n";
  116.       RunQuery($Param);
  117.       if (defined $3) {
  118.         $Param->{CID}->{$2} = $3 ;
  119.         #print "DB:$Param->{CID}->{$2} .. $2 .. $3 \n";
  120.       }
  121.     }
  122.  
  123.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Quit\s+$/i) { # remove connection ID($2) and querystring
  124.       #print "Q-$1--$2--------\n";
  125.       RunQuery($Param);
  126.       delete $Param->{CID}->{$2} ;
  127.     }
  128.  
  129.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(select.+)$/i) { # get connection ID($2) and querystring
  130.       #print "S1-$1--$2--$3------\n";
  131.       RunQuery($Param);
  132.       unless ($Param->{CID}->{$2}) {
  133.         #print "Error: No Database for Handle: $2 found\n";
  134.       }
  135.       else {
  136.         $Param->{DB}=$Param->{CID}->{$2};
  137.  
  138.         my $s = "$3";
  139.         $s =~ s/from\s/from $Param->{DB}./i;
  140.         $Param->{Query}="EXPLAIN $s";
  141.  
  142.         #$s =~ m/from\s+(\w+[.]\w+)/i;
  143.         #$Param->{tab} =$1;
  144.         #print "-- $Param->{tab} -- $s --\n";
  145.       }
  146.     }
  147.  
  148.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(update.+)$/i) { # get connection ID($2) and querystring
  149.       #print "S2--$1--$2--$3------\n";
  150.       RunQuery($Param);
  151.       unless ($Param->{CID}->{$2}) {
  152.         #print "Error: No Database for Handle: $2 found\n";
  153.       }
  154.       else {
  155.         $Param->{DB}=$Param->{CID}->{$2};
  156.  
  157.         my $ud = $3;
  158.         $ud =~ m/^update\s+(\w+).+(where.+)$/i;
  159.         $Param->{Query} ="EXPLAIN SELECT * FROM $1 $2";
  160.         $Param->{Query} =~ s/from\s/from $Param->{DB}./i;
  161.  
  162.         #$Param->{Query} =~ m/from\s+(\w+[.]\w+)/i;
  163.         #$Param->{tab} =$1;
  164.       }
  165.     }
  166.  
  167.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Statistics\s+(.*)$/i) { # get connection ID($2) and info?
  168.       $Param->{Statistics} ++;
  169.       #print "Statistics--$1--$2--$3------\n";
  170.       RunQuery($Param);
  171.     }
  172.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Query\s+(.+)$/i) { # get connection ID($2)
  173.       $Param->{QueryCount} ++;
  174.       #print "Query-NULL $3\n";
  175.       RunQuery($Param);
  176.     }
  177.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Refresh\s+(.+)$/i) { # get connection ID($2)
  178.       $Param->{Refresh} ++;
  179.       #print "Refresh\n";
  180.       RunQuery($Param);
  181.     }
  182.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Init\s+(.+)$/i) { # get connection ID($2)
  183.       $Param->{Init} ++;
  184.       #print "Init $3\n";
  185.       RunQuery($Param);
  186.     }
  187.     elsif (m/^(\d{6}\s+\d{1,2}:\d\d:\d\d\s+|\s+)(\d+)\s+Field\s+(.+)$/i) { # get connection ID($2)
  188.       $Param->{Field} ++;
  189.       #print "Field $3\n";
  190.       RunQuery($Param);
  191.     }
  192.  
  193.     elsif (m/^\s+(.+)$/ ) { # command could be some lines ...
  194.       #print "multi-lined ($1)\n";
  195.       my ($A)=$1;
  196.        chomp $A;
  197.       $Param->{Query} .= " $1";
  198.       #print "multi-lined ($1)<<$Param->{Query}>>\n";
  199.     }
  200.  
  201.  
  202.       }
  203.  
  204.     }
  205.  
  206.     $Param->{dbh}->disconnect();
  207.  
  208.     if (1 == 0) {
  209.       print "\nunclosed handles----------------------------------------\n";
  210.       my $count=0;
  211.       foreach (sort keys %{$Param->{CID}}) {
  212.     print "$count | $_ : $Param->{CID}->{$_} \n";
  213.     $count ++;
  214.       }
  215.     }
  216.  
  217.     print "\nIndex usage ------------------------------------\n";
  218.     foreach my $t (sort keys %{$Param->{Data}}) {
  219.       print "\nTable\t$t: ---\n";
  220.       foreach my $k (sort keys %{$Param->{Data}->{$t}}) {
  221.     print " count\t$k:\n";
  222.     my %h = %{$Param->{Data}->{$t}->{$k}};
  223.       foreach (sort {$h{$a} <=> $h{$b}} keys %h) {
  224.       print "  $Param->{Data}->{$t}->{$k}->{$_}\t$_\n";
  225.     }
  226.       }
  227.     }
  228.  
  229.     $Param->{AllCount}=0;
  230.     print "\nQueries causing table scans -------------------\n\n";
  231.     foreach (@{$Param->{ALL}}) {
  232.       $Param->{AllCount} ++;
  233.       print "$_\n";
  234.     }
  235.     print "Sum: $Param->{AllCount} table scans\n";
  236.  
  237.     print "\nSummary ---------------------------------------\n\n";
  238.     print "Select: \t$Param->{SelectCount} queries\n";
  239.     print "Update: \t$Param->{UpdateCount} queries\n";
  240.     print "\n";
  241.  
  242.     print "Init:   \t$Param->{Init} times\n";
  243.     print "Field:  \t$Param->{Field} times\n";
  244.     print "Refresh: \t$Param->{Refresh} times\n";
  245.     print "Query:  \t$Param->{QueryCount} times\n";
  246.     print "Statistics:\t$Param->{Statistics} times\n";
  247.     print "\n";
  248.  
  249.     print "Logfile: \t$Param->{LineCount} lines\n";
  250.     print "Started:  \t".localtime($Param->{Start})."\n";
  251.     print "Finished:   \t".localtime(time)."\n";
  252.  
  253.   }
  254.  
  255.  
  256. ###########################################################################
  257. #
  258. #
  259. #
  260. sub RunQuery {
  261.   my $Param = shift ;
  262.  
  263.   if (defined $Param->{Query}) {
  264.     if (defined $Param->{DB} ) {
  265.  
  266.       $Param->{Query} =~ m/from\s+(\w+[.]\w+|\w+)/i;
  267.       $Param->{tab} =$1;
  268.       #print "||$Param->{tab} -- $Param->{Query}\n";
  269.  
  270.       my $sth=$Param->{dbh}->prepare("USE $Param->{DB}");
  271.       if (DBI::err()) {
  272.     if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
  273.       }
  274.       else {
  275.     $sth->execute();
  276.     if (DBI::err()) {
  277.       if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
  278.     }
  279.     else {
  280.       $sth->finish();
  281.  
  282.       $sth=$Param->{dbh}->prepare($Param->{Query});
  283.       if (DBI::err()) {
  284.         if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
  285.       }
  286.       else {
  287.         #print "$Param->{Query}\n";
  288.         $sth->execute();
  289.         if (DBI::err()) {
  290.           if ($Param->{PrintError}) {print "[$Param->{LineCount}]<<$Param->{Query}>>\n";}
  291.           if ($Param->{PrintError}) {print "Error: ".DBI::errstr()."\n";}
  292.         }
  293.         else {
  294.           my $row = undef;
  295.           while ($row = $sth->fetchrow_hashref()) {
  296.         $Param->{SelectCount} ++;
  297.  
  298.         if (defined $row->{Comment}) {
  299.           push (@{$Param->{Comment}}, "$row->{Comment}; $_; $Param->{DB}; $Param->{Query}");
  300.         }
  301.         foreach (@{$Param->{Rows}}) {
  302.           if (defined $row->{$_}) {
  303.             #if (($_ eq 'type' ) and ($row->{$_} eq 'ALL')) {
  304.             if ($row->{type} eq 'ALL') {
  305.               push (@{$Param->{ALL}}, "$Param->{Query}");
  306.               #print ">> $row->{$_} $_ $Param->{DB} $Param->{Query}\n";
  307.             }
  308.             $Param->{IdxUseCount} ++;
  309.             $Param->{Data}->{$Param->{tab}}->{$_}->{$row->{$_}} ++;
  310.           }
  311.         }
  312.           }
  313.         }
  314.       }
  315.     }
  316.       }
  317.       $sth->finish();
  318.     }
  319.     $Param->{Query} = undef ;
  320.   }
  321. }
  322.  
  323. ###########################################################################
  324. #
  325. #
  326. #
  327. sub ShowOptions {
  328.   print <<EOF;
  329. Usage: $0 [OPTIONS] < LOGFILE
  330.  
  331. --help, -h
  332.     Display this help message
  333. --date=YYMMDD, -d=YYMMDD
  334.     Select entries from the log only for the given date
  335. --host=HOSTNAME, -h=HOSTNAME
  336.     Connect to the MySQL server on the given host
  337. --user=USERNAME, -u=USERNAME
  338.     The MySQL username to use when connecting to the server
  339. --password=PASSWORD, -p=PASSWORD
  340.     The password to use when connecting to the server
  341. --socket=SOCKET, -s=SOCKET
  342.     The socket file to use when connecting to the server
  343. --printerror=1, -e 1
  344.     Enable error output
  345.  
  346. mysql_explain_log reads its standard input for query log contents. It
  347. uses EXPLAIN to analyze SELECT statements found in the input. UPDATE
  348. statements are rewritten to SELECT statements and also analyzed with
  349. EXPLAIN. mysql_explain_log then displays a summary of its results.
  350. Results are printed to the standard output.
  351. EOF
  352. }
  353.  
  354. 1;
  355.  
  356. __END__
  357.  
  358. =pod
  359.  
  360. =head1 NAME
  361.  
  362. mysql_explain_log
  363.  
  364. Feed a mysqld general query logfile (created with mysqld --log) back
  365. into mysql and collect statistics about index usage with EXPLAIN.
  366.  
  367. =head1 DISCUSSION
  368.  
  369. To optimize your indexes, you must know which ones are actually used
  370. and what kind of queries are causing table scans. This may not be easy,
  371. especially if you are generating your queries dynamically and you have
  372. a huge number of queries being executed.
  373.  
  374. Use this tool to take a look at the effects of your real life queries.
  375. Then add indexes to avoid table scans and remove indexes that aren't used.
  376.  
  377. =head1 USAGE
  378.  
  379. mysql_explain_log [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] [--socket=/path/to/socket] [--printerror=1] < logfile
  380.  
  381. --help, -h
  382.     Display this help message
  383. --date=YYMMDD, -d=YYMMDD
  384.     Select entries from the log only for the given date
  385. --host=HOSTNAME, -h=HOSTNAME
  386.     Connect to the MySQL server on the given host
  387. --user=USERNAME, -u=USERNAME
  388.     The MySQL username to use when connecting to the server
  389. --password=PASSWORD, -p=PASSWORD
  390.     The password to use when connecting to the server
  391. --socket=SOCKET, -s=SOCKET
  392.     The socket file to use when connecting to the server
  393. --printerror=1, -e 1
  394.     Enable error output
  395.  
  396. =head1 EXAMPLE
  397.  
  398. mysql_explain_log --host=localhost --user=foo --password=bar < /var/lib/mysql/mobile.log
  399.  
  400. =head1 AUTHORS
  401.  
  402.   Stefan Nitz
  403.   Jan Willamowius <jan@willamowius.de>, http://www.willamowius.de
  404.   Dennis Haney <davh@davh.dk> (Added socket support)
  405.  
  406. =head1 SEE ALSO
  407.  
  408. mysql documentation
  409.  
  410. =cut
  411.