<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MySQL Expert &#124; MySQL Performance &#124; MySQL Consulting &#187; query analysis</title>
	<atom:link href="http://ronaldbradford.com/blog/tag/query-analysis/feed/" rel="self" type="application/rss+xml" />
	<link>http://ronaldbradford.com/blog</link>
	<description>Expert times and information on MySQL</description>
	<lastBuildDate>Tue, 07 Sep 2010 18:45:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Optimizing SQL Performance &#8211; The Art of Elimination</title>
		<link>http://ronaldbradford.com/blog/optimizing-sql-performance-the-art-of-elimination-2010-07-08/</link>
		<comments>http://ronaldbradford.com/blog/optimizing-sql-performance-the-art-of-elimination-2010-07-08/#comments</comments>
		<pubDate>Thu, 08 Jul 2010 17:19:24 +0000</pubDate>
		<dc:creator>ronald</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Professional]]></category>
		<category><![CDATA[cary millsap]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[query analysis]]></category>

		<guid isPermaLink="false">http://ronaldbradford.com/blog/?p=3005</guid>
		<description><![CDATA[The most efficient performance optimization of a SQL statement is to eliminate it.  Cary Millsap&#8217;s recent Kaleidoscope presentation again highlighted that improving performance is function of code path. Removing code will improve performance.
You may think that it could be hard to eliminate SQL, however when you know every SQL statement that is executed in [...]]]></description>
			<content:encoded><![CDATA[<p>The most efficient performance optimization of a SQL statement is to eliminate it.  <a href="http://carymillsap.blogspot.com/">Cary Millsap&#8217;s</a> recent <a href="http://www.technicalconferencesolutions.com/pls/caat/caat_abstract_reports.display_presenter_abstract?conference_id=68&#038;presenter_id=90&#038;abstract_id=473">Kaleidoscope presentation</a> again highlighted that improving performance is function of code path. Removing code will improve performance.</p>
<p>You may think that it could be hard to eliminate SQL, however when you know every SQL statement that is executed in your code path obvious improvements may be possible.  In the sequence SQL was implemented sometimes easy observations can lead to great gains.  Let me provide some actual client examples that were discovered by using the MySQL General Log.</p>
<h3>Example 1</h3>
<pre>
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist` WHERE (ArtistID = 196 )
5 Query   SELECT *  FROM `artist` WHERE (ArtistID = 2188 )
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist`
5 Query   SELECT *  FROM `artist`
</pre>
<p>In this example, the following was executed for a single page load.  Not only did I find a bug where full-table scans occurred rather then being qualified, there were many repeating and unnecessary occurrences.</p>
<h3>Example 2</h3>
<pre>
SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes'
SELECT option_value FROM wp_options WHERE option_name = 'aiosp_title_format' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_show_only_even' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_num_months' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_day_length' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_hide_event_box' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_advanced' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_navigation' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'ec3_disable_popups' LIMIT 1
SELECT option_value FROM wp_options WHERE option_name = 'sidebars_widgets' LIMIT 1
</pre>
<p>This is a stock <a href="http://wordpress.org">Wordpress</a> installation and highlights a classic Row at a Time (RAT) processing.</p>
<h3>Example 3</h3>
<pre>
SELECT * FROM activities_theme WHERE theme_parent_id=0
SELECT * FROM activities_theme WHERE theme_parent_id=1
SELECT * FROM activities_theme WHERE theme_parent_id=2
SELECT * FROM activities_theme WHERE theme_parent_id=11
SELECT * FROM activities_theme WHERE theme_parent_id=16
</pre>
<p>In this client example, again RAT processing, I provided a code improvement to run these multiple queries in a single statement, otherwise known as Chunk At a Time (CAT) processing.  It&#8217;s not rocket science however the elimination of the network component of several SQL statements can greatly reduce page load time.</p>
<pre>
SELECT *
FROM   activities_theme
WHERE  theme_parent_id in  (0,1,2,11,16) 
</pre>
<h3>Example 4</h3>
<p>The following represents one of the best improvement. During capture, the following query was executed 6,000 times over a 5 minute period. While you make think this is acceptable, the value passed wae 0.  The pages_id is an auto_increment column which by definition does not have a 0 value.  In this instance, a simple boundary condition in the code would eliminate this query.</p>
<pre>
SELECT pages_id, pages_livestats_code, pages_title,
       pages_parent, pages_exhibid, pages_theme,
       pages_accession_num
FROM pages WHERE pages_id = 0
</pre>
<p>There are many tips to improving and optimizing SQL. This is the simplest and often overlooked starting point.</p>
]]></content:encoded>
			<wfw:commentRss>http://ronaldbradford.com/blog/optimizing-sql-performance-the-art-of-elimination-2010-07-08/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SQL Analysis with MySQL Proxy &#8211; Part 2</title>
		<link>http://ronaldbradford.com/blog/sql-analysis-with-mysql-proxy-part-2-2009-09-03/</link>
		<comments>http://ronaldbradford.com/blog/sql-analysis-with-mysql-proxy-part-2-2009-09-03/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 16:31:19 +0000</pubDate>
		<dc:creator>ronald</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Drizzle]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Proxy]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Professional]]></category>
		<category><![CDATA[Gearman]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[query analysis]]></category>

		<guid isPermaLink="false">http://ronaldbradford.com/blog/?p=1883</guid>
		<description><![CDATA[As I outlined in Part 1 MySQL Proxy can be one tool for performing SQL analysis.  The impact with any monitoring is the art of monitoring will affect the results, in this case the performance.  I don&#8217;t recommend enabling this level of detailed monitoring in production, these techniques are designed for development, testing, [...]]]></description>
			<content:encoded><![CDATA[<p>As I outlined in <a href="http://ronaldbradford.com/blog/sql-query-analysis-with-mysql-proxy-2009-09-02/">Part 1</a> MySQL Proxy can be one tool for performing SQL analysis.  The impact with any monitoring is the art of monitoring will affect the results, in this case the performance.  I don&#8217;t recommend enabling this level of detailed monitoring in production, these techniques are designed for development, testing, and possibly stress testing.</p>
<p>This leads to the question, how do I monitor SQL in production? The simple answer to this question is, Sampling.  Take a representative sample of your production system. The implementation of this depends on many factors including your programming technology stack, and your MySQL topology.</p>
<p>If for example you are using PHP, then defining MySQL proxy on a production system, and <a href="http://forge.mysql.com/tools/tool.php?id=82">executing firewall rules</a> to redirect incoming 3306 traffic to 4040 for a period of time, e.g. 2 seconds can provide a wealth of information as to what&#8217;s happening on the server now.  I have used this very successfully in production as an information gathering an analysis tool.  It is also reasonably easy to configure, execute and the impact on any failures for example are minimized due to the sampling time.</p>
<p>If you run a distributed environment with MySQL Slaves, or many application servers, you can also introduce sampling to a certain extent as these specific points, however like scaling options, it is key to be able to handle and process the write load accurately.</p>
<p>Another performance improvement is to move processing of the gathered information in MySQL proxy to a separate thread or process, removing this work from the thread execution path and therefore increasing the performance.  I&#8217;m interested to explore the option of passing this information off to memcached or gearman and having MySQL proxy simply capture the packet information and distributing the output.  I have yet to see how memcached and/or gearman integrate with the Lua/C bindings.  If anybody has experience or knowledge I would be interested to know more.</p>
<p>It is interesting to know that Drizzle provides a plugin to send this level of logging information to gearman automatically.</p>
]]></content:encoded>
			<wfw:commentRss>http://ronaldbradford.com/blog/sql-analysis-with-mysql-proxy-part-2-2009-09-03/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL query analysis with MySQL Proxy</title>
		<link>http://ronaldbradford.com/blog/sql-query-analysis-with-mysql-proxy-2009-09-02/</link>
		<comments>http://ronaldbradford.com/blog/sql-query-analysis-with-mysql-proxy-2009-09-02/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 00:34:10 +0000</pubDate>
		<dc:creator>ronald</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Proxy]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Professional]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[query analysis]]></category>
		<category><![CDATA[query analyzer]]></category>

		<guid isPermaLink="false">http://ronaldbradford.com/blog/?p=1863</guid>
		<description><![CDATA[Long before there was the official Query Analyzer (QUAN), a component of MySQL Enterprise, SQL analysis was possible using MySQL Proxy.
The following is an introduction to logging and query analysis with MySQL Proxy.
Get MySQL Proxy
You need to first download MySQL Proxy. In this example I am using the Linux RHEL5 64bit OS and Version 0.7.2

$ [...]]]></description>
			<content:encoded><![CDATA[<p>Long before there was the official Query Analyzer (QUAN), a component of MySQL Enterprise, SQL analysis was possible using <a href="http://forge.mysql.com/wiki/MySQL_Proxy">MySQL Proxy</a>.</p>
<p>The following is an introduction to logging and query analysis with MySQL Proxy.</p>
<h3>Get MySQL Proxy</h3>
<p>You need to first <a href="http://dev.mysql.com/downloads/mysql-proxy/">download MySQL Proxy</a>. In this example I am using the Linux RHEL5 64bit OS and Version 0.7.2</p>
<pre>
$ wget http://dev.mysql.com/get/Downloads/MySQL-Proxy/mysql-proxy-0.7.2-linux-rhel5-x86-64bit.tar.gz/from/http://mirror.trouble-free.net/mysql_mirror/
$ tar xvfz mysql-proxy-0.7.2-linux-rhel5-x86-64bit.tar.gz
$ ln -s mysql-proxy-0.7.2-linux-rhel5-x86-64bit mysql-proxy
$ export PATH=`pwd`/mysql-proxy/sbin:$PATH
$ mysql-proxy --help-all
</pre>
<h3>Pre-requisites</h3>
<p>MySQL Proxy uses TCP/IP, so it is important you connect via the actual hostname.  You should first confirm this, as appropriate MySQL permissions may be necessary. For example:</p>
<pre>
$ mysql -h`hostname` -u -p
</pre>
<p>On confirmation this works, you can then connect directly to the proxy</p>
<pre>
$ mysql -h`hostname` -P4040 -u -p
</pre>
<h3>Logging</h3>
<pre>
$ cd mysql-proxy/share/doc/mysql-proxy/
$ wget -O log.lua http://ronaldbradford.com/mysql-dba/mysql-proxy/log.lua
$ mysql-proxy --proxy-lua-script=share/doc/mysql-proxy/log.lua &#038;
$ tail -f mysql.log
</pre>
<p>This script is based on <a href="http://forge.mysql.com/tools/tool.php?id=80">simple query logging</a> which requires a modification to work in more current versions of MySQL proxy.</p>
<pre>
$ mysql -hhostname -P4040 -u -p
mysql>  SELECT host,user,password FROM mysql.user;
mysql>  SELECT table_schema,COUNT(*) FROM information_schema.tables GROUP BY table_schema;
mysql>  SELECT NOW(), SLEEP(3);
mysql>  EXIT
</pre>
<pre>
$ cat mysql.log
2009-09-02 17:15:01     58 -- select @@version_comment limit 1
2009-09-02 17:16:15     58 -- SELECT host,user,password FROM mysql.user
2009-09-02 17:16:30     58 -- SELECT table_schema,COUNT(*) FROM information_schema.tables GROUP BY table_schema
2009-09-02 17:16:39     58 -- SELECT NOW(), SLEEP(3)
</pre>
<h3>Query Analysis</h3>
<p>Restart proxy with the histogram.lua sample provided.</p>
<pre>
$ mysql-proxy --proxy-lua-script=share/doc/mysql-proxy/histogram.lua &#038;
</pre>
<p>Connect and run some queries.</p>
<pre>
$ mysql -hhostname -P4040 -u -p
mysql>  SELECT host,user,password FROM mysql.user;
mysql>  SELECT table_schema,COUNT(*) FROM information_schema.tables GROUP BY table_schema;
mysql>  SELECT NOW(), SLEEP(3);
</pre>
<p>While connected to the proxy, you can now review data from two pseudo tables.</p>
<pre>
mysql>  SELECT * FROM histogram.tables;
mysql>  SELECT * FROM histogram.queries\G
mysql>  DELETE FROM histogram.tables;
mysql>  DELETE FROM histogram.queries;

mysql> SELECT * FROM histogram.tables;
+---------------------------+-------+--------+
| table                     | reads | writes |
+---------------------------+-------+--------+
| information_schema.tables |     1 |      0 |
| mysql.user                |     1 |      0 |
+---------------------------+-------+--------+

mysql> SELECT * FROM histogram.queries;
+--------------------------------------------------------------------------------------------------+-------+----------------+----------------+
| query                                                                                            | count | max_query_time | avg_query_time |
+--------------------------------------------------------------------------------------------------+-------+----------------+----------------+
| SELECT @@version_comment LIMIT ?                                                                 |     1 |            300 |            300 |
| SELECT `table_schema` , COUNT( * ) FROM `information_schema` . `tables` GROUP BY `table_schema`  |     1 |           1822 |           1822 |
| SELECT `host` , `user` , `password` FROM `mysql` . `user`                                        |     1 |            494 |            494 |
| SELECT NOW( ) , SLEEP( ? )                                                                       |     1 |        3000735 |        3000735 |
+--------------------------------------------------------------------------------------------------+-------+----------------+----------------+
</pre>
<h3>Moving forward</h3>
<p>The power is that with Lua you have the flexibility to write your own logging.  Some improvements to these scripts could be.</p>
<ul>
<li>Add the query time, number of rows, and result set size to the logging</li>
<li>Be able to sort histogram results or see top percentile. Being able to copy data into real tables would enable any level of analysis</li>
<li>Combine the logging and histogram scripts</li>
<li>Enable global enable/disabling of logging with SET GLOBAL commands</li>
<li>Support variable length IN queries, those that pass multiple values, so you end up with a subset of all queries</li>
<li>Provide a actual query example, making it easy to do a QEP. For normalized queries you need to do additional work to find values.</li>
<li>The histogram does not support the C API multi query functionality, where multiple queries can be passed to the server at one time. The problem is there is no way to time the individual queries.</li>
</ul>
<p>Read on in <a href="http://ronaldbradford.com/blog/sql-analysis-with-mysql-proxy-part-2-2009-09-03/">SQL Analysis with MySQL Proxy &#8211; Part 2</a>.</p>
<h3>References</h3>
<p><a href="http://www.oreillynet.com/pub/a/databases/2007/07/12/getting-started-with-mysql-proxy.html">A good introduction document</a><br />
<a href="http://www.slideshare.net/ronaldbradford/mysql-proxy-from-architecture-to-implementation">MySQL Proxy &#8211; From architecture to implementation</a> &#8211; OSCON 2008</p>
]]></content:encoded>
			<wfw:commentRss>http://ronaldbradford.com/blog/sql-query-analysis-with-mysql-proxy-2009-09-02/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
