<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title>Comments on: Slow Query Log analyzes tools</title>
	<atom:link href="http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/</link>
	<description>Everything about MySQL Performance</description>
	<pubDate>Sun, 07 Sep 2008 07:55:02 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
		<item>
		<title>By: peter</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-350659</link>
		<dc:creator>peter</dc:creator>
		<pubDate>Sun, 31 Aug 2008 18:08:08 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-350659</guid>
		<description>There is patch for 5.0.62
http://www.mysqlperformanceblog.com/mysql-patches/

We also have patch in work for 5.0.67

If you need patch for 5.0.61 or any other version we can do backport on consulting basics.</description>
		<content:encoded><![CDATA[<p>There is patch for 5.0.62<br />
<a href="http://www.mysqlperformanceblog.com/mysql-patches/" rel="nofollow">http://www.mysqlperformanceblog.com/mysql-patches/</a></p>
<p>We also have patch in work for 5.0.67</p>
<p>If you need patch for 5.0.61 or any other version we can do backport on consulting basics.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ilkka</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-350495</link>
		<dc:creator>Ilkka</dc:creator>
		<pubDate>Sun, 31 Aug 2008 01:33:33 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-350495</guid>
		<description>Hi,

Is it possible to update the patch to 5.0.61? Thanks.</description>
		<content:encoded><![CDATA[<p>Hi,</p>
<p>Is it possible to update the patch to 5.0.61? Thanks.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Adam Loving&#8217;s Blog &#187; Blog Archive &#187; MySQL Slow Query Log analyzer script</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-333874</link>
		<dc:creator>Adam Loving&#8217;s Blog &#187; Blog Archive &#187; MySQL Slow Query Log analyzer script</dc:creator>
		<pubDate>Thu, 24 Jul 2008 15:45:35 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-333874</guid>
		<description>[...] Filed Under (Uncategorized) by admin on 19-06-1950     This perl script is easy to run and it rolls up the contents of your mysql-slow.log to show you not only which queries are slow, but which are called most often. Source:http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/ [...]</description>
		<content:encoded><![CDATA[<p>[...] Filed Under (Uncategorized) by admin on 19-06-1950     This perl script is easy to run and it rolls up the contents of your mysql-slow.log to show you not only which queries are slow, but which are called most often. Source:http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/ [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: links for 2008-06-11 &#171; Gatunogatuno&#8217;s Weblog</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-312388</link>
		<dc:creator>links for 2008-06-11 &#171; Gatunogatuno&#8217;s Weblog</dc:creator>
		<pubDate>Wed, 11 Jun 2008 12:41:35 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-312388</guid>
		<description>[...]  Slow Query Log analyzes tools &#124; MySQL Performance Blog (tags: article database development MySQL performance) [...]</description>
		<content:encoded><![CDATA[<p>[...]  Slow Query Log analyzes tools | MySQL Performance Blog (tags: article database development MySQL performance) [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: GBA</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-312001</link>
		<dc:creator>GBA</dc:creator>
		<pubDate>Tue, 10 Jun 2008 15:23:21 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-312001</guid>
		<description>Here's how i used this patch to benchmark our production server:

First, I enabled the general query log in my production server, and collected some data.  I let it run for 60 hours (2 1/2 days), which captured peak times, and all typical usage.
I used a trick to turn off the general query log without restarting mysql - i moved the log file aside, touched a replacement, but didn't give the mysql user write permision to it.  I then used mysqladmin to flush all the logs, and when it couldn't open a handle to the new general query log file, it simply stopped logging.

Now, get an identical piece of hardware as your production server - preferably built by clonig the HDD so you have identical OS and filesystem layout.
Recompile the same version of mysql, with this patch applied (we compile mysql from source ourselves anyway, so this is still a fair performance test).  Get the database on it current up to the point you turned on the general query log.
To do this, i used a backup from a few weeks earlier, and used mysqlbinlog to extract the rest of the data from the binary logs, up until the start point.  I could actually see the last line in the catchup sql matching one of the first in the general query log, so rewinded one second, and knew i was spot on.
You now have an identical server, with data in a state ready to be benchmarked.
It's worth taking a database dump here, in case you want to run the benchmark again.

Now pump your query log acquired earlier through the below perl script.  It's very quick, very dirty, and probably very buggy, but seemed to work acceptably well in our case.
It rebuilds the timing, connections, and queries the server saw, based on the contents of query log - it creates a seperate thread for each connection, and runs each query at (about) the right time, relative to the start of the run.
That means if you have 60 hours worth of dump data, the script will run for 60 hours replaying it.  This was important for us, because we have short bursts of very high load, long periods of quite low load, and even the odd moment of practically zero load.  This recreates all of them, just like they were in real life.
It's worth running this script on a seperate box with lot's of cores - it's very thread-hungry.


The script (replay_query_log.pl):


#!perl


use Time::Local;
use DBI();


# Setup who your DB host host, and a hash of copnnection passwords.
# You need one password entry for each user that connects
#  in the logs you want to replay - you can get by grepping
#  for 'Connect', and using cut/sed/sort/uniq liberally.
#
my $DBHOST="slush";
my %passwords = ( "user"        =&#62; "pass",
                  "reporting"   =&#62; "reporting",
                  "user-no-pw"  =&#62; "",
                  "etc"         =&#62; "etc"
                );

# skip the first 3 lines
();
();
();


# Process the query log, and build a couple of hashes from it:
#
# Hash 1: %queries - keyed by connection id and datetime,
#       - is an array of all queries by that connection at that time.
# Hash 2: %starttime - keyed by connection id
#       - contains the time the first query run by this conenction started
#
# The first hash is used to actually runt he queries, the second is used to
#  avoid fork bombing the box, by only forking the processes when needed.

while ()
{
        # datetime line
        if(s/^(0[0-9])([01][0-9])([0-3][0-9])\s+(1?[0-9]):([0-5][0-9]):([0-5][0-9])//)
        {
                # Convert to unix epoch - makes date arithmetic dead easy.
                $datetime = Time::Local::timelocal($6, $5, $4, $3, $2-1, "20".$1);
                $dt_min = $datetime if (($datetime &#60; $dt_min) &#124;&#124; !(defined $dt_min));
        }
        # query type line
        if(s/^\s+([0-9]+) ((Query)&#124;(Quit)&#124;(Connect)&#124;(Statistics)&#124;(Binlog Dump Log))//)
        {
                # If we enter this loop, it means a new query/type has started.
                # Save the old one (if it exists), and reinitialise the vars
                #  for the next
                push @{$queries{$connection}{$datetime}}, $query if length($query);
                $connection = $1;
                $starttime{$connection} = $datetime if (($datetime  $_)
        {
                sleep $now - $_;
        }
        # Now that the threads are due to start, we fork, and connect
        foreach (@{$startconn{$_}})
        {
                my $conn = $_;
                my $DBUSER = $dbun{$conn}[0];
                my $DBNAME = $dbun{$conn}[1];
                my $DBPASS = $passwords{$DBUSER};
                my $pid = fork();
                if($pid == 0)
                {
                        ###print "forked\n";
                        my $dbh;
                        # Each connection has multiple queries, so we
                        #  iterate the hash, waiting for the correct time
                        #  to run each one.
                        # I use while(){ sleep 1 } rather than sleep n to
                        #  avoid timing issues - this garauntees the query will
                        #  run within +/- 0.5s of when it's due, which is good
                        #  enough for our purposes (usually).
                        foreach (sort keys %{$queries{$conn}})
                        {
                                my $dt = $_;
                                while((time() - $offset) connect("DBI:mysql:database=$DBNAME;host=$DBHOST",
                                                                        "$DBUSER", "$DBPASS")
                                                                        &#124;&#124; die "Couldn't create dbh";
                                }
                                foreach (@{$queries{$conn}{$_}})
                                {
                                        my $sth = $dbh-&#62;prepare($_);
                                        $sth-&#62;execute();
                                        $sth-&#62;finish();
                                }
                        }
                        $dbh-&#62;disconnect();
                        ###print "died\n";
                        exit;  # very important.
                } else
                {
                        # Don't do this.
                        #waitpid($pid,0);
                }
        }
}

# done!!!








I got some quite interesting numbers our of it, and have learned a lot about how our database behaves.


Now - this is not a well tested script - it's probably rife with bugs, so use with caution.  Any bugfixes, enhancements, or comments - please post them back here.




Hopefully this will help some-one else out.</description>
		<content:encoded><![CDATA[<p>Here&#8217;s how i used this patch to benchmark our production server:</p>
<p>First, I enabled the general query log in my production server, and collected some data.  I let it run for 60 hours (2 1/2 days), which captured peak times, and all typical usage.<br />
I used a trick to turn off the general query log without restarting mysql - i moved the log file aside, touched a replacement, but didn&#8217;t give the mysql user write permision to it.  I then used mysqladmin to flush all the logs, and when it couldn&#8217;t open a handle to the new general query log file, it simply stopped logging.</p>
<p>Now, get an identical piece of hardware as your production server - preferably built by clonig the HDD so you have identical OS and filesystem layout.<br />
Recompile the same version of mysql, with this patch applied (we compile mysql from source ourselves anyway, so this is still a fair performance test).  Get the database on it current up to the point you turned on the general query log.<br />
To do this, i used a backup from a few weeks earlier, and used mysqlbinlog to extract the rest of the data from the binary logs, up until the start point.  I could actually see the last line in the catchup sql matching one of the first in the general query log, so rewinded one second, and knew i was spot on.<br />
You now have an identical server, with data in a state ready to be benchmarked.<br />
It&#8217;s worth taking a database dump here, in case you want to run the benchmark again.</p>
<p>Now pump your query log acquired earlier through the below perl script.  It&#8217;s very quick, very dirty, and probably very buggy, but seemed to work acceptably well in our case.<br />
It rebuilds the timing, connections, and queries the server saw, based on the contents of query log - it creates a seperate thread for each connection, and runs each query at (about) the right time, relative to the start of the run.<br />
That means if you have 60 hours worth of dump data, the script will run for 60 hours replaying it.  This was important for us, because we have short bursts of very high load, long periods of quite low load, and even the odd moment of practically zero load.  This recreates all of them, just like they were in real life.<br />
It&#8217;s worth running this script on a seperate box with lot&#8217;s of cores - it&#8217;s very thread-hungry.</p>
<p>The script (replay_query_log.pl):</p>
<p>#!perl</p>
<p>use Time::Local;<br />
use DBI();</p>
<p># Setup who your DB host host, and a hash of copnnection passwords.<br />
# You need one password entry for each user that connects<br />
#  in the logs you want to replay - you can get by grepping<br />
#  for &#8216;Connect&#8217;, and using cut/sed/sort/uniq liberally.<br />
#<br />
my $DBHOST=&#8221;slush&#8221;;<br />
my %passwords = ( &#8220;user&#8221;        =&gt; &#8220;pass&#8221;,<br />
                  &#8220;reporting&#8221;   =&gt; &#8220;reporting&#8221;,<br />
                  &#8220;user-no-pw&#8221;  =&gt; &#8220;&#8221;,<br />
                  &#8220;etc&#8221;         =&gt; &#8220;etc&#8221;<br />
                );</p>
<p># skip the first 3 lines<br />
();<br />
();<br />
();</p>
<p># Process the query log, and build a couple of hashes from it:<br />
#<br />
# Hash 1: %queries - keyed by connection id and datetime,<br />
#       - is an array of all queries by that connection at that time.<br />
# Hash 2: %starttime - keyed by connection id<br />
#       - contains the time the first query run by this conenction started<br />
#<br />
# The first hash is used to actually runt he queries, the second is used to<br />
#  avoid fork bombing the box, by only forking the processes when needed.</p>
<p>while ()<br />
{<br />
        # datetime line<br />
        if(s/^(0[0-9])([01][0-9])([0-3][0-9])\s+(1?[0-9]):([0-5][0-9]):([0-5][0-9])//)<br />
        {<br />
                # Convert to unix epoch - makes date arithmetic dead easy.<br />
                $datetime = Time::Local::timelocal($6, $5, $4, $3, $2-1, &#8220;20&#8243;.$1);<br />
                $dt_min = $datetime if (($datetime &lt; $dt_min) || !(defined $dt_min));<br />
        }<br />
        # query type line<br />
        if(s/^\s+([0-9]+) ((Query)|(Quit)|(Connect)|(Statistics)|(Binlog Dump Log))//)<br />
        {<br />
                # If we enter this loop, it means a new query/type has started.<br />
                # Save the old one (if it exists), and reinitialise the vars<br />
                #  for the next<br />
                push @{$queries{$connection}{$datetime}}, $query if length($query);<br />
                $connection = $1;<br />
                $starttime{$connection} = $datetime if (($datetime  $_)<br />
        {<br />
                sleep $now - $_;<br />
        }<br />
        # Now that the threads are due to start, we fork, and connect<br />
        foreach (@{$startconn{$_}})<br />
        {<br />
                my $conn = $_;<br />
                my $DBUSER = $dbun{$conn}[0];<br />
                my $DBNAME = $dbun{$conn}[1];<br />
                my $DBPASS = $passwords{$DBUSER};<br />
                my $pid = fork();<br />
                if($pid == 0)<br />
                {<br />
                        ###print &#8220;forked\n&#8221;;<br />
                        my $dbh;<br />
                        # Each connection has multiple queries, so we<br />
                        #  iterate the hash, waiting for the correct time<br />
                        #  to run each one.<br />
                        # I use while(){ sleep 1 } rather than sleep n to<br />
                        #  avoid timing issues - this garauntees the query will<br />
                        #  run within +/- 0.5s of when it&#8217;s due, which is good<br />
                        #  enough for our purposes (usually).<br />
                        foreach (sort keys %{$queries{$conn}})<br />
                        {<br />
                                my $dt = $_;<br />
                                while((time() - $offset) connect(&#8221;DBI:mysql:database=$DBNAME;host=$DBHOST&#8221;,<br />
                                                                        &#8220;$DBUSER&#8221;, &#8220;$DBPASS&#8221;)<br />
                                                                        || die &#8220;Couldn&#8217;t create dbh&#8221;;<br />
                                }<br />
                                foreach (@{$queries{$conn}{$_}})<br />
                                {<br />
                                        my $sth = $dbh-&gt;prepare($_);<br />
                                        $sth-&gt;execute();<br />
                                        $sth-&gt;finish();<br />
                                }<br />
                        }<br />
                        $dbh-&gt;disconnect();<br />
                        ###print &#8220;died\n&#8221;;<br />
                        exit;  # very important.<br />
                } else<br />
                {<br />
                        # Don&#8217;t do this.<br />
                        #waitpid($pid,0);<br />
                }<br />
        }<br />
}</p>
<p># done!!!</p>
<p>I got some quite interesting numbers our of it, and have learned a lot about how our database behaves.</p>
<p>Now - this is not a well tested script - it&#8217;s probably rife with bugs, so use with caution.  Any bugfixes, enhancements, or comments - please post them back here.</p>
<p>Hopefully this will help some-one else out.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Federico Feroldi&#8217;s blog &#187; Blog Archive &#187; links for 2008-05-13</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-298507</link>
		<dc:creator>Federico Feroldi&#8217;s blog &#187; Blog Archive &#187; links for 2008-05-13</dc:creator>
		<pubDate>Tue, 13 May 2008 20:35:39 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-298507</guid>
		<description>[...] Slow Query Log analyzes tools &#124; MySQL Performance Blog MySQL has simple but quite handy feature - slow query log, which allows you to log all queries which took over define number of seconds to execute. (tags: analysis article database log monitoring mysql performance tuning query slow tool) [...]</description>
		<content:encoded><![CDATA[<p>[...] Slow Query Log analyzes tools | MySQL Performance Blog MySQL has simple but quite handy feature - slow query log, which allows you to log all queries which took over define number of seconds to execute. (tags: analysis article database log monitoring mysql performance tuning query slow tool) [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: iddaa</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-296682</link>
		<dc:creator>iddaa</dc:creator>
		<pubDate>Thu, 08 May 2008 11:39:49 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-296682</guid>
		<description>Hello,
What should be the long_query_time for best performance?
Regards</description>
		<content:encoded><![CDATA[<p>Hello,<br />
What should be the long_query_time for best performance?<br />
Regards</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: MySQL-慢查询</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-267949</link>
		<dc:creator>MySQL-慢查询</dc:creator>
		<pubDate>Mon, 07 Apr 2008 06:22:44 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-267949</guid>
		<description>[...] Slow Query Log analyzes tools [...]</description>
		<content:encoded><![CDATA[<p>[...] Slow Query Log analyzes tools [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: MySQL 优化之 Slow Query Log &#187; Dream of space</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-266235</link>
		<dc:creator>MySQL 优化之 Slow Query Log &#187; Dream of space</dc:creator>
		<pubDate>Sat, 05 Apr 2008 00:55:44 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-266235</guid>
		<description>[...] 1 秒钟)。可以通过 Microslow Patch 来解决这个问题(粒度可以到百万分之一秒)。这个 Patch [...]</description>
		<content:encoded><![CDATA[<p>[...] 1 秒钟)。可以通过 Microslow Patch 来解决这个问题(粒度可以到百万分之一秒)。这个 Patch [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: peter</title>
		<link>http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-232649</link>
		<dc:creator>peter</dc:creator>
		<pubDate>Tue, 22 Jan 2008 11:43:13 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/2006/09/06/slow-query-log-analyzes-tools/#comment-232649</guid>
		<description>Right. It also allows it to be 0 to log all queries with their times.</description>
		<content:encoded><![CDATA[<p>Right. It also allows it to be 0 to log all queries with their times.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
