<?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>code.openark.org &#187; Analysis</title>
	<atom:link href="http://code.openark.org/blog/tag/analysis/feed" rel="self" type="application/rss+xml" />
	<link>http://code.openark.org/blog</link>
	<description>Blog by Shlomi Noach</description>
	<lastBuildDate>Wed, 01 Feb 2012 08:19:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>common_schema, rev. 178: foreach(), repeat_exec(), Roland Bouman, query analysis</title>
		<link>http://code.openark.org/blog/mysql/common_schema-rev-178-foreach-repeat_exec-roland-bouman-query-analysis</link>
		<comments>http://code.openark.org/blog/mysql/common_schema-rev-178-foreach-repeat_exec-roland-bouman-query-analysis#comments</comments>
		<pubDate>Thu, 01 Dec 2011 09:33:01 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[common_schema]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Stored routines]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4133</guid>
		<description><![CDATA[common_schema, revision 178 is now released, with major additions. This revision turns common_schema into a framework, rather than a set of views and functions. common_schema provides with query scripting, analysis &#38; informational views, and a function library, allowing for easier administration and diagnostics for MySQL. It introduces SQL based tools which simplify otherwise complex shell [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/common-schema/" rel="nofollow">common_schema</a>, revision <strong>178</strong> is now released, with major additions. This revision turns <em>common_schema</em> into a <em>framework</em>, rather than a set of views and functions.</p>
<p><em>common_schema</em> provides with query scripting, analysis &amp; informational views, and a function library, allowing for easier administration and diagnostics for MySQL. It introduces SQL based tools which simplify otherwise complex shell and client scripts, allowing the DBA to be independent of operating system, installed packages and dependencies.</p>
<p>There's no Perl nor Python, and no dependencies to install. It's just a <em>schema</em>.</p>
<p>Some highlights for the new revision:</p>
<ul>
<li><strong>foreach()</strong>, aka <strong>$()</strong>: loop through a collection, execute callback commands per element.</li>
<li><strong>repeat_exec()</strong>: a repeat-until device: execute queries until some condition holds.</li>
<li><strong>exec_file()</strong>: execute files a-la SOURCE, but on server side</li>
<li><strong>Query analysis</strong>: analyze query text, view or routine definitions to detect dependency objects.</li>
<li>Improvements to views and routines, new routines introduced.</li>
</ul>
<p>Let's take a closer look:</p>
<h4>rpbouman</h4>
<p>I'm very happy to have <a href="http://rpbouman.blogspot.com/">Roland Bouman</a> working on this project. He introduced some sophisticated code without which some functionality could not take place. I'm sure I don't need to introduce his great capabilities; I'll just pass the note that it is very good working with him!</p>
<h4>foreach()</h4>
<p>Introducing a looping device which can iterate a collection and execute callback commands.</p>
<p>What's a collection? A range of numbers; a set of constants; the result set of a <strong>SELECT</strong> query; tables in your database and more.</p>
<p>What is a callback? A query or set of queries to invoke on the specific elements in the collection. For example:</p>
<blockquote>
<pre>call <strong>foreach</strong>(<span style="color: #808000;">'table in sakila'</span>, <span style="color: #000080;">'ALTER TABLE ${schema}.${table} ENGINE=InnoDB ROW_FORMAT=COMPRESSED'</span>);</pre>
</blockquote>
<p>I'll publish dedicated posts on <em>foreach()</em>, aka <em>$()</em>, following this post. Official documentation is <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/foreach.html">here</a>.</p>
<h4>repeat_exec()</h4>
<p>Repeat executing queries in a given interval, until some condition holds.</p>
<p>What kind of condition? You can loop forever, or until a given time has passed, a given number of iteration has passed.<span id="more-4133"></span></p>
<p>You can iterate until no rows are affected by your commands (your callbacks), or until some dynamic condition holds (a query evaluates to <strong>true</strong>).</p>
<p>For example: purge rows from a table until no more rows are affected; in interval of <strong>3</strong> second:</p>
<blockquote>
<pre>call <strong>repeat_exec</strong>(3, 'DELETE FROM test.event WHERE ts &lt; CURDATE() ORDER BY id LIMIT 1000', 0);</pre>
</blockquote>
<p>Official documentation is <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/repeat_exec.html">here</a>.</p>
<h4>exec_file()</h4>
<p>If you need to execute commands from a file, you usually invoke SOURCE:</p>
<blockquote>
<pre>mysql&gt; SOURCE '/tmp/somefile.sql';</pre>
</blockquote>
<p>Or you invoke mysql client and redirect its input to read from file:</p>
<blockquote>
<pre>bash$ mysql some_db &lt; /tmp/somefile.sql</pre>
</blockquote>
<p><strong>SOURCE</strong> is a MySQL client command. The file must reside on your client. Running the <strong>mysql</strong> client is great, but you need to work it out from <em>outside</em> the server.</p>
<p><em>call_exec()</em> will let you import a file <em>on server side</em>, from <em>within the server</em>:</p>
<blockquote>
<pre>call <strong>exec_file</strong>('/tmp/some_file.sql');</pre>
</blockquote>
<p>You will need to have the file readable; it is limited to 64K at this moment; it may not use DELIMITER, and it may not include dynamic SQL. These are the limitations.</p>
<p>Official documentation is <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/exec_file.html">here</a>.</p>
<h4>exec() / exec_single()</h4>
<p>All of the above rely on the <em>exec()</em> / <em>exec_single()</em> routines, which dynamically execute a set of queries. One one hand, it's no big deal: they only have to use prepared statements in order to invoke the queries. But then, they knows how to parse multiple queries (find the ";" delimiter correctly), plus they allow for configuration: if you set <strong>@common_schema_dryrun</strong>, queries are not actually executes; just printed out. If you set <strong>@common_schema_verbose</strong>, queries are verbosed in addition to being executed. Since all execution routines rely on these,we get a standardized pattern.</p>
<p>Official documentation <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/exec_single.html">is</a> <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/exec.html">here</a>.</p>
<h4>Query analysis</h4>
<p>Query parsing routines allow for detection of dependencies within queries. While not full-blown SQL parser, these allow one to realize on which tables or routines a view depends on; or a routines depends on; or an event; or just any query.</p>
<p>These routines can analyze the text of not only a <strong>SELECT</strong> query, but also <strong>UPDATE</strong>, <strong>DELETE</strong>, <strong>CREATE</strong>, etc. They can read the code of a stored routines, including queries and control flow constructs; thus, they are also able to analyze events and triggers.</p>
<p>At this stage forward-dependencies resolution is supported. This can eventually lead to dependency graphs or to reverse-dependency resolution (i.e. "which view, routine, trigger or event depend on table <strong>t</strong>?")</p>
<p>Example:</p>
<blockquote>
<pre>mysql&gt; call <strong>get_view_dependencies</strong>('sakila', 'actor_info');
+-------------+---------------+-------------+--------+
| schema_name | object_name   | object_type | action |
+-------------+---------------+-------------+--------+
| sakila      | actor         | table       | select |
| sakila      | category      | table       | select |
| sakila      | film          | table       | select |
| sakila      | film_actor    | table       | select |
| sakila      | film_category | table       | select |
+-------------+---------------+-------------+--------+</pre>
</blockquote>
<p>The query analysis routines are in BETA stage.</p>
<p>Official documentation is <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/query_analysis_routines.html">here</a>.</p>
<h4>Test quite</h4>
<p><em>common_schema</em> is now tested. Not all code is as yet under tests; all new code is, and some of the older code. Work is in progress to add more and more tests.</p>
<h4>Further changes:</h4>
<ul>
<li><strong>candidate_keys</strong> does not give higher score for <strong>PRIMARY KEY</strong>s any longer. It ranks all unique keys according to its own heuristic; it also provides with the  <strong>is_primary</strong> and <strong>is_nullable</strong> columns.</li>
<li>Added <strong>candidate_keys_recommended</strong> view, recommending best candidate key per table (while noting whether it qualifies as <strong>PRIMARY KEY</strong> in terms of <strong>NULL</strong>able columns).</li>
<li>Added many text parsing and text manipulation routines, such as better trim, tokenizing, etc. Improved existing code significantly.</li>
</ul>
<h4>Get it</h4>
<p><em>common_schema</em> is <a href="http://code.google.com/p/common-schema/">available for downloaded</a>. It is released under the <strong>BSD</strong> license, and is free.</p>
<p>I've put very hard work into <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/introduction.html">common_schema's documentation</a>. It is very thorough and provides with clear examples. The documentation is also available for download.</p>
<p>If you encounter problems, <a href="http://code.google.com/p/common-schema/issues/list">please report on the issues page</a>.</p>
<p><em>common_schema</em> is meant to be downloaded &amp; installed on any MySQL server. It provides with general and essential functionality. Spread the word!</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/common_schema-rev-178-foreach-repeat_exec-roland-bouman-query-analysis/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL Global status difference using single query</title>
		<link>http://code.openark.org/blog/mysql/mysql-global-status-difference-using-single-query</link>
		<comments>http://code.openark.org/blog/mysql/mysql-global-status-difference-using-single-query#comments</comments>
		<pubDate>Fri, 12 Aug 2011 16:31:12 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[common_schema]]></category>
		<category><![CDATA[INFORMATION_SCHEMA]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=3908</guid>
		<description><![CDATA[Have just read MySQL Global status difference using MySQL procedures / functions, by Andres Karlsson. Have commented, but realized I did not provide with a direct answer. In the comment, I suggested checking out a solution based on views, found in common_schema. But the solution in common_schema is split into two views, due to the [...]]]></description>
			<content:encoded><![CDATA[<p>Have just read <a href="http://karlssonondatabases.blogspot.com/2011/08/mysql-global-status-difference-using_12.html">MySQL Global status difference using MySQL procedures / functions</a>, by Andres Karlsson. Have commented, but realized I did not provide with a direct answer. In the comment, I suggested checking out <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/global_status_diff.html">a solution based on views</a>, found in <a rel="nofollow" href="http://code.google.com/p/common-schema/">common_schema</a>. But the solution in <em>common_schema</em> is split into two views, due to the fact views cannot handle derived tables subqueries.</p>
<p>Well, here's a single query to do that: it checks <strong>GLOBAL_STATUS</strong> twice, <strong>10</strong> seconds apart in the following sample. It uses <strong>SLEEP()</strong> to actually wait between the two reads. Yes, you can do that with a query.</p>
<p>The following query shows all <strong>GLOBAL_STATUS</strong> values that have changed during the sample period.<span id="more-3908"></span></p>
<blockquote>
<pre>SELECT STRAIGHT_JOIN
   LOWER(gs0.VARIABLE_NAME) AS variable_name,
   gs0.VARIABLE_VALUE AS variable_value_0,
   gs1.VARIABLE_VALUE AS variable_value_1,
   (gs1.VARIABLE_VALUE - gs0.VARIABLE_VALUE) AS variable_value_diff,
   (gs1.VARIABLE_VALUE - gs0.VARIABLE_VALUE) / 10 AS variable_value_psec,
   (gs1.VARIABLE_VALUE - gs0.VARIABLE_VALUE) * 60 / 10 AS
variable_value_pminute
FROM
   (
     SELECT
       VARIABLE_NAME,
       VARIABLE_VALUE
     FROM
       INFORMATION_SCHEMA.GLOBAL_STATUS
     UNION ALL
     SELECT
       '',
       SLEEP(10)
     FROM DUAL
   ) AS gs0
   JOIN INFORMATION_SCHEMA.GLOBAL_STATUS gs1 USING (VARIABLE_NAME)
WHERE
   gs1.VARIABLE_VALUE != gs0.VARIABLE_VALUE
;
+-----------------------------------+------------------+------------------+---------------------+---------------------+------------------------+
| variable_name                     | variable_value_0 | variable_value_1 | variable_value_diff | variable_value_psec | variable_value_pminute |
+-----------------------------------+------------------+------------------+---------------------+---------------------+------------------------+
| aborted_clients                   | 2210669          | 2210686          |                  17 |                 1.7 |                    102 |
| bytes_received                    | 53259933210      | 53260211104      |              277894 |             27789.4 |                1667364 |
| bytes_sent                        | 351130988015     | 351132884956     |             1896941 |            189694.1 |               11381646 |
| com_change_db                     | 3760546          | 3760584          |                  38 |                 3.8 |                    228 |
| com_delete                        | 6774784          | 6774801          |                  17 |                 1.7 |                    102 |
| com_insert                        | 52743750         | 52744012         |                 262 |                26.2 |                   1572 |
| com_insert_select                 | 13362650         | 13362740         |                  90 |                   9 |                    540 |
| com_select                        | 51722818         | 51723107         |                 289 |                28.9 |                   1734 |
| com_set_option                    | 108564134        | 108564754        |                 620 |                  62 |                   3720 |
| com_show_collations               | 3760530          | 3760568          |                  38 |                 3.8 |                    228 |
| com_show_processlist              | 366078           | 366082           |                   4 |                 0.4 |                     24 |
| com_show_status                   | 366047           | 366051           |                   4 |                 0.4 |                     24 |
| com_show_variables                | 3760535          | 3760573          |                  38 |                 3.8 |                    228 |
| com_update                        | 6271283          | 6271324          |                  41 |                 4.1 |                    246 |
| connections                       | 3781382          | 3781420          |                  38 |                 3.8 |                    228 |
| created_tmp_disk_tables           | 983223           | 983224           |                   1 |                 0.1 |                      6 |
| created_tmp_tables                | 9134044          | 9134126          |                  82 |                 8.2 |                    492 |
| handler_commit                    | 125798040        | 125798688        |                 648 |                64.8 |                   3888 |
| handler_delete                    | 6849562          | 6849578          |                  16 |                 1.6 |                     96 |
| handler_read_first                | 5332451          | 5332498          |                  47 |                 4.7 |                    282 |
| handler_read_key                  | 373910509        | 373912469        |                1960 |                 196 |                  11760 |
| handler_read_next                 | 850122025        | 850170403        |               48378 |              4837.8 |                 290268 |
| handler_read_rnd                  | 255104660        | 255105932        |                1272 |               127.2 |                   7632 |
| handler_read_rnd_next             | 992505444        | 992549948        |               44504 |              4450.4 |                 267024 |
| handler_update                    | 27930283         | 27930465         |                 182 |                18.2 |                   1092 |
| handler_write                     | 2051582925       | 2051602416       |               19491 |              1949.1 |                 116946 |
| innodb_buffer_pool_pages_data     | 77232            | 77243            |                  11 |                 1.1 |                     66 |
| innodb_buffer_pool_pages_dirty    | 626              | 645              |                  19 |                 1.9 |                    114 |
| innodb_buffer_pool_pages_flushed  | 38429812         | 38430032         |                 220 |                  22 |                   1320 |
| innodb_buffer_pool_pages_misc     | 4294922063       | 4294922052       |                 -11 |                -1.1 |                    -66 |
| innodb_buffer_pool_read_requests  | 1933796064       | 1933871603       |               75539 |              7553.9 |                 453234 |
| innodb_buffer_pool_reads          | 11360212         | 11360214         |                   2 |                 0.2 |                     12 |
| innodb_buffer_pool_write_requests | 1074109722       | 1074115394       |                5672 |               567.2 |                  34032 |
| innodb_data_fsyncs                | 5583880          | 5583905          |                  25 |                 2.5 |                    150 |
| innodb_data_read                  | 3339489280       | 3339501568       |               12288 |              1228.8 |                  73728 |
| innodb_data_reads                 | 11796492         | 11796494         |                   2 |                 0.2 |                     12 |
| innodb_data_writes                | 105587582        | 105588145        |                 563 |                56.3 |                   3378 |
| innodb_data_written               | 3721600000       | 3727315968       |             5715968 |            571596.8 |               34295808 |
| innodb_dblwr_pages_written        | 38429812         | 38430032         |                 220 |                  22 |                   1320 |
| innodb_dblwr_writes               | 596503           | 596506           |                   3 |                 0.3 |                     18 |
| innodb_log_write_requests         | 380978894        | 380981368        |                2474 |               247.4 |                  14844 |
| innodb_log_writes                 | 74407604         | 74407990         |                 386 |                38.6 |                   2316 |
| innodb_os_log_fsyncs              | 2310799          | 2310807          |                   8 |                 0.8 |                     48 |
| innodb_os_log_written             | 2905292800       | 2906502656       |             1209856 |            120985.6 |                7259136 |
| innodb_pages_created              | 1341584          | 1341593          |                   9 |                 0.9 |                     54 |
| innodb_pages_read                 | 13117652         | 13117654         |                   2 |                 0.2 |                     12 |
| innodb_pages_written              | 38429812         | 38430032         |                 220 |                  22 |                   1320 |
| innodb_rows_deleted               | 6849552          | 6849568          |                  16 |                 1.6 |                     96 |
| innodb_rows_inserted              | 43787980         | 43788207         |                 227 |                22.7 |                   1362 |
| innodb_rows_read                  | 4289845136       | 4289919560       |               74424 |              7442.4 |                 446544 |
| innodb_rows_updated               | 24119627         | 24119809         |                 182 |                18.2 |                   1092 |
| key_read_requests                 | 41262330         | 41262338         |                   8 |                 0.8 |                     48 |
| open_files                        | 7                | 5                |                  -2 |                -0.2 |                    -12 |
| opened_files                      | 4212920          | 4212924          |                   4 |                 0.4 |                     24 |
| questions                         | 253158874        | 253160331        |                1457 |               145.7 |                   8742 |
| select_full_join                  | 546              | 547              |                   1 |                 0.1 |                      6 |
| select_range                      | 721945           | 721947           |                   2 |                 0.2 |                     12 |
| select_scan                       | 12828865         | 12828989         |                 124 |                12.4 |                    744 |
| sort_range                        | 170971           | 170973           |                   2 |                 0.2 |                     12 |
| sort_rows                         | 255175383        | 255176655        |                1272 |               127.2 |                   7632 |
| sort_scan                         | 534078           | 534080           |                   2 |                 0.2 |                     12 |
| table_locks_immediate             | 142673687        | 142674454        |                 767 |                76.7 |                   4602 |
| threads_cached                    | 7                | 8                |                   1 |                 0.1 |                      6 |
| threads_connected                 | 5                | 10               |                   5 |                 0.5 |                     30 |
| threads_created                   | 840486           | 840509           |                  23 |                 2.3 |                    138 |
+-----------------------------------+------------------+------------------+---------------------+---------------------+------------------------+</pre>
</blockquote>
<p>Some values don't make sense to do difference on (e.g. <strong>threads_connected</strong>), since they present with momentary status and are not incrementing as others (e.g. <strong>threads_created</strong>).</p>
<p>Happy SQLing!</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/mysql-global-status-difference-using-single-query/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Announcing common_schema: common views &amp; routines for MySQL</title>
		<link>http://code.openark.org/blog/mysql/announcing-common_schema-common-views-routines-for-mysql</link>
		<comments>http://code.openark.org/blog/mysql/announcing-common_schema-common-views-routines-for-mysql#comments</comments>
		<pubDate>Wed, 13 Jul 2011 04:25:24 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[common_schema]]></category>
		<category><![CDATA[Data Types]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Indexing]]></category>
		<category><![CDATA[INFORMATION_SCHEMA]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[Monitoring]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Schema]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Stored routines]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=3794</guid>
		<description><![CDATA[Today I have released common_schema, a utility schema for MySQL which includes many views and functions, and is aimed to be installed on any MySQL server. What does it do? There are views answering for all sorts of useful information: stuff related to schema analysis, data dimensions, monitoring, processes &#38; transactions, security, internals... There are [...]]]></description>
			<content:encoded><![CDATA[<p>Today I have released <a title="common_schema" href="http://code.openark.org/forge/common_schema">common_schema</a>, a utility schema for MySQL which includes many views and functions, and is aimed to be installed on any MySQL server.</p>
<h4>What does it do?</h4>
<p>There are views answering for all sorts of useful information: stuff related to schema analysis, data dimensions, monitoring, processes &amp; transactions, security, internals... There are basic functions answering for common needs.</p>
<p>Some of the views/routines simply formalize those queries we tend to write over and over again. Others take the place of external tools, answering complex questions via SQL and metadata. Still others help out with SQL generation.</p>
<p>Here are a few highlights:</p>
<ul>
<li>Did you know you can work out <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/global_status_diff_nonzero.html">simple monitoring</a> of your server with a <em>query</em>?  There's a view to do that for you.</li>
<li>How about showing just <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/processlist_top.html">the good parts of the processlist</a>?</li>
<li>Does your schema have <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/redundant_keys.html">redundant keys</a>?</li>
<li>Or InnoDB tables with <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/no_pk_innodb_tables.html">no PRIMARY KEY</a>?</li>
<li>Is AUTO_INCREMENT <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/auto_increment_columns.html">running out of space</a>?</li>
<li>Can I get the SQL statements to <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/sql_foreign_keys.html">generate my FOREIGN KEYs</a>? To drop them?</li>
<li>And can we finally get <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/sql_show_grants.html">SHOW GRANTS for all accounts</a>, and as an <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/sql_grants.html">SQL query</a>?</li>
<li>Ever needed a <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/general_functions.html#crc64">64 bit CRC function</a>?</li>
<li>And aren't you tired of writing the cumbersome SUBSTRING_INDEX(SUBSTRING_INDEX(str, ',', 3), ',', -1)? <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/string_functions.html#split_token">There's an alternative</a>.</li>
</ul>
<p>There's more. Take a look at the <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/introduction.html">common_schema documentation</a> for full listing. And it's evolving: I've got quite a few ideas already for future components.</p>
<p>Some of these views rely on heavyweight INFORMATION_SCHEMA tables. You should be aware of the impact and <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/risks.html">risks</a>.</p>
<h4>What do I need to install?</h4>
<p>There's no script or executable file. It's just a schema. The distribution in an SQL file which generates <em>common_schema</em>. Much like a dump file.</p>
<h4><span id="more-3794"></span>What are the system requirements?</h4>
<p>It's just between you and your MySQL. There are currently three distribution files, dedicated for different versions of MySQL (and allowing for increased functionality):</p>
<ul>
<li><strong>common_schema_mysql_51</strong>: fits all MySQL &gt;= 5.1 distributions</li>
<li><strong>common_schema_innodb_plugin</strong>: fits MySQL &gt;= 5.1, with InnoDB plugin + INFORMATION_SCHEMA tables enabled</li>
<li><strong>common_schema_percona_server</strong>: fits Percona Server &gt;= 5.1</li>
</ul>
<p>Refer to the <a rel="nofollow" href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/download.html">documentation</a> for more details.</p>
<h4>What are the terms of use?</h4>
<p><em>common_schema</em> is released under the <a href="http://www.opensource.org/licenses/bsd-license.php">BSD license</a>.</p>
<h4>Where can I download it?</h4>
<p>On the <a href="http://code.google.com/p/common-schema/">common_schema project page</a>. Enjoy it!</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/announcing-common_schema-common-views-routines-for-mysql/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Checking for AUTO_INCREMENT capacity with single query</title>
		<link>http://code.openark.org/blog/mysql/checking-for-auto_increment-capacity-with-single-query</link>
		<comments>http://code.openark.org/blog/mysql/checking-for-auto_increment-capacity-with-single-query#comments</comments>
		<pubDate>Tue, 05 Apr 2011 05:36:56 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[INFORMATION_SCHEMA]]></category>
		<category><![CDATA[openark kit]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=3421</guid>
		<description><![CDATA[Darn! This means oak-show-limits becomes redundant. Am I not supposed to speak about it on my coming presentation? Bad timing! You have AUTO_INCREMENT columns. How far are you pushing the limits? Are you going to run out of AUTO_INCREMENT values soon? Perhaps you wonder whether you should ALTER from INT to BIGINT? The answer is [...]]]></description>
			<content:encoded><![CDATA[<p><em>Darn!</em> This means <a href="http://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/oak-show-limits.html">oak-show-limits</a> becomes redundant. Am I not supposed to speak about it on my <a href="http://en.oreilly.com/mysql2011/public/schedule/detail/17155">coming presentation</a>? Bad timing!</p>
<p>You have <strong>AUTO_INCREMENT</strong> columns. How far are you pushing the limits? Are you going to run out of <strong>AUTO_INCREMENT</strong> values soon? Perhaps you wonder whether you should <strong>ALTER</strong> from <strong>INT</strong> to <strong>BIGINT</strong>?</p>
<p>The answer is all there in <strong>INFORMATION_SCHEMA</strong>. The <strong>TABLES</strong> table shows the current <strong>AUTO_INCREMENT</strong> value per table, and the <strong>COLUMNS</strong> table tells us all about a column's data type.</p>
<p>It takes some ugly code to deduce the maximum value per column type, what with signed/unsigned and data type, but then its very simple. Here is the query:<span id="more-3421"></span></p>
<blockquote>
<pre>SELECT
  TABLE_SCHEMA,
  TABLE_NAME,
  COLUMN_NAME,
  DATA_TYPE,
  COLUMN_TYPE,
  IF(
    LOCATE('unsigned', COLUMN_TYPE) &gt; 0,
    1,
    0
  ) AS IS_UNSIGNED,
  (
    CASE DATA_TYPE
      WHEN 'tinyint' THEN 255
      WHEN 'smallint' THEN 65535
      WHEN 'mediumint' THEN 16777215
      WHEN 'int' THEN 4294967295
      WHEN 'bigint' THEN 18446744073709551615
    END &gt;&gt; IF(LOCATE('unsigned', COLUMN_TYPE) &gt; 0, 0, 1)
  ) AS MAX_VALUE,
  AUTO_INCREMENT,
  AUTO_INCREMENT / (
    CASE DATA_TYPE
      WHEN 'tinyint' THEN 255
      WHEN 'smallint' THEN 65535
      WHEN 'mediumint' THEN 16777215
      WHEN 'int' THEN 4294967295
      WHEN 'bigint' THEN 18446744073709551615
    END &gt;&gt; IF(LOCATE('unsigned', COLUMN_TYPE) &gt; 0, 0, 1)
  ) AS AUTO_INCREMENT_RATIO
FROM
  INFORMATION_SCHEMA.COLUMNS
  INNER JOIN INFORMATION_SCHEMA.TABLES USING (TABLE_SCHEMA, TABLE_NAME)
WHERE
  TABLE_SCHEMA NOT IN ('mysql', 'INFORMATION_SCHEMA', 'performance_schema')
  AND EXTRA='auto_increment'
;
</pre>
</blockquote>
<p>There's one row in the result set for each <strong>AUTO_INCREMENT</strong> column. since at most one <strong>AUTO_INCREMENT</strong> column can exist for any given table, each row also identifies a unique table. Resulting columns are mostly self-explanatory, but here's some details on some of the columns:</p>
<ul>
<li><strong>IS_UNSIGNED</strong>: <strong>1</strong> when the column is <strong>UNSIGNED</strong>, <strong>0</strong> otherwise.</li>
<li><strong>MAX_VALUE</strong>: maximum value that can be contained within column.</li>
<li><strong>AUTO_INCREMENT</strong>: current <strong>AUTO_INCREMENT</strong> value for table.</li>
<li><strong>AUTO_INCREMENT_RATIO</strong>: value in the range <strong>[0..1]</strong>, where <strong>1</strong> means "100% full".</li>
</ul>
<p>A sample output:</p>
<blockquote>
<pre>+--------------+------------+--------------+-----------+-----------------------+-------------+------------+----------------+----------------------+
| TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME  | DATA_TYPE | COLUMN_TYPE           | IS_UNSIGNED | MAX_VALUE  | AUTO_INCREMENT | AUTO_INCREMENT_RATIO |
+--------------+------------+--------------+-----------+-----------------------+-------------+------------+----------------+----------------------+
| sakila       | actor      | actor_id     | smallint  | smallint(5) unsigned  |           1 |      65535 |            201 |               0.0031 |
| sakila       | address    | address_id   | smallint  | smallint(5) unsigned  |           1 |      65535 |            606 |               0.0092 |
| sakila       | category   | category_id  | tinyint   | tinyint(3) unsigned   |           1 |        255 |             17 |               0.0667 |
| sakila       | city       | city_id      | smallint  | smallint(5) unsigned  |           1 |      65535 |            601 |               0.0092 |
| sakila       | country    | country_id   | smallint  | smallint(5) unsigned  |           1 |      65535 |            110 |               0.0017 |
| sakila       | customer   | customer_id  | smallint  | smallint(5) unsigned  |           1 |      65535 |            600 |               0.0092 |
| sakila       | film       | film_id      | smallint  | smallint(5) unsigned  |           1 |      65535 |           1001 |               0.0153 |
| sakila       | inventory  | inventory_id | mediumint | mediumint(8) unsigned |           1 |   16777215 |           4582 |               0.0003 |
| sakila       | language   | language_id  | tinyint   | tinyint(3) unsigned   |           1 |        255 |              7 |               0.0275 |
| sakila       | payment    | payment_id   | smallint  | smallint(5) unsigned  |           1 |      65535 |          16050 |               0.2449 |
| sakila       | rental     | rental_id    | int       | int(11)               |           0 | 2147483647 |          16050 |               0.0000 |
| sakila       | staff      | staff_id     | tinyint   | tinyint(3) unsigned   |           1 |        255 |              3 |               0.0118 |
| sakila       | store      | store_id     | tinyint   | tinyint(3) unsigned   |           1 |        255 |              3 |               0.0118 |
+--------------+------------+--------------+-----------+-----------------------+-------------+------------+----------------+----------------------+
</pre>
</blockquote>
<h4>Bonus: free advice on increasing your AUTO_INCREMENT capacity</h4>
<p>Make it <strong>UNSIGNED</strong>. No, really. Check your definitions now.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/checking-for-auto_increment-capacity-with-single-query/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>oak-hook-general-log: your poor man&#039;s Query Analyzer</title>
		<link>http://code.openark.org/blog/mysql/oak-hook-general-log-your-poor-mans-query-analyzer</link>
		<comments>http://code.openark.org/blog/mysql/oak-hook-general-log-your-poor-mans-query-analyzer#comments</comments>
		<pubDate>Wed, 15 Dec 2010 17:46:06 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=3032</guid>
		<description><![CDATA[The latest release of openark kit introduces oak-hook-general-log, a handy tool which allows for some analysis of executing queries. Initially I just intended for the tool to be able to dump the general log to standard output, from any machine capable to connect to MySQL. Quick enough, I realized the power it brings. With this [...]]]></description>
			<content:encoded><![CDATA[<p>The latest release of <a href="http://code.openark.org/forge/openark-kit">openark kit</a> introduces <a href="http://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/oak-hook-general-log.html">oak-hook-general-log</a>, a handy tool which allows for some analysis of executing queries.</p>
<p>Initially I just intended for the tool to be able to dump the general log to standard output, from any machine capable to connect to MySQL. Quick enough, I realized the power it brings.</p>
<p>With this tool, one can dump to standard output all queries using temporary tables; or using a specific index; or doing a full index scan; or just follow up on connections; or... For example, the following execution will only log queries which make for filesort:</p>
<blockquote>
<pre>oak-hook-general-log --user=root --host=localhost --password=123456 --filter-explain-filesort</pre>
</blockquote>
<h4>The problem with using the standard logs</h4>
<p>So you have the <em>general log</em>, which you don't often enable, since it tends to grow huge within moments. You then have the <em>slow log</em>. Slow log is great, and is among the top tools for MySQL diagnosis.</p>
<p>The slow log allows for <strong>log-queries-not-using-indexes</strong>, which is yet another nice feature. Not only should you log any query running for over <strong>X</strong> seconds, but also log any query which does not use an index.</p>
<p>Wait. This logs all single-row tables (no single row table will use an index), as well as very small tables (a common <strong>20</strong> rows lookup table will most often be scanned). These are OK scans. This makes for some noise in the slow log.</p>
<p>And how about queries which do use an index, but do so poorly? They use an index, but retrieve some <strong>12,500,000</strong> rows, <em>using temporary</em> table &amp; <em>filesort</em>?</p>
<h4>What oak-hook-general-log does for you</h4>
<p>This tool streams out the general log, and filters out queries based on their <em>role</em> or on their <em>execution plan</em>.</p>
<p>To work at all, it must enable the general log. Moreover, it directs the general log to log table. Mind that this makes for a performance impact, which is why the tool auto-terminates and restores original log settings (default is <strong>1</strong> minute, configurable). It's really not a tool you should keep running for days. But during the few moments it runs, it will:</p>
<ul>
<li>Routinely rotate the <strong>mysql.general_log</strong> table so that it doesn't fill up</li>
<li>Examine entries found in the general log</li>
<li>Cross reference entries to the PROCESSLIST so as to deduce database context (<a href="http://bugs.mysql.com/bug.php?id=52554">bug #52554</a>)</li>
<li>If required and appropriate, evaluate a query's execution plan</li>
<li>Decide whether to dump each entry based on filtering rules</li>
</ul>
<h4>Filtering rules</h4>
<p>Filtering rules are passed as command line options. At current, only one filtering rule applies (if more than one specified only one is used, so no point in passing more than one). Some of the rules are:<span id="more-3032"></span></p>
<ul>
<li><strong>filter-connection</strong>: only log connect/quit entries</li>
<li><strong>filter-explain-fullscan</strong>: only log full table scans</li>
<li><strong>filter-explain-temporary</strong>: only log queries which create implicit temporary tables</li>
<li><strong>filter-explain-rows-exceed</strong>: only log queries where more than <strong>X</strong> number of rows are being accessed on some table (estimated)</li>
<li><strong>filter-explain-total-rows-exceed</strong>: only log queries where more than <strong>X</strong> number of rows are accessed on all tables combined (estimated, with possibly incorrect numbers on some queries)</li>
<li><strong>filter-explain-key</strong>: only log queries using a specific index. This feature somewhat overlaps with Maatkit's <em>mk-index-usage</em> (read <a href="http://www.mysqlperformanceblog.com/2010/11/11/advanced-index-analysis-with-mk-index-usage/">announcement</a>).</li>
<li><strong>filter-explain-contains</strong>: a general purpose <em>grep</em> on the execution plan. Log queries where the execution plan contains <em>some text</em>.</li>
</ul>
<p>There are other filters, and I will possibly add more in due time.</p>
<p>Here are a couple cases I used <em>oak-hook-general-log</em> for:</p>
<h4>Use case: temporary tables</h4>
<p>I have a server with this alarming chart (courtesy <a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a>) of temporary tables:</p>
<blockquote>
<pre><img class="alignnone" title="Created tmp tables per second" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=370x180&amp;chts=303030,12&amp;chtt=Latest+24+hours:+Dec+9,+06:30++-++Dec+10,+06:30&amp;chf=c,s,ffffff&amp;chdl=created_tmp_tables_psec|created_tmp_disk_tables_psec&amp;chdlp=b&amp;chco=ff8c00,4682b4&amp;chd=s:yzzy02zzz100zzz0rv9zz0zyzyz0yy2xz1t11xzztz0xr1xt2tz07vwzz100100z31z111yz1vzzzzz1zs80r902s1111010y20z03z11487zz011z11011002w0q5rxxz0y00z0s02xy1yy0,gggfghggfgggghhgYekhhghhhhhghfjghhdihfhgdghgZhgcicihpcehhhhhhhifkigjihghjehgiigjgYqiYqgiaihiifkhekhfijgiihhggggggggggfhgghffZoYgggggggggdihfggghg&amp;chxt=x,y&amp;chxr=1,0,35.060000&amp;chxl=0:||08:00||+||12:00||+||16:00||+||20:00||+||00:00||+||04:00||+|&amp;chxs=0,505050,10,0,lt&amp;chg=4.17,25,1,2,2.08,0&amp;chxp=0,2.08,6.25,10.42,14.59,18.76,22.93,27.10,31.27,35.44,39.61,43.78,47.95,52.12,56.29,60.46,64.63,68.80,72.97,77.14,81.31,85.48,89.65,93.82,97.99&amp;tsstart=2010-12-09+06:30:00&amp;tsstep=600" alt="" width="370" height="180" />
</pre>
</blockquote>
<p>What could possibly create <strong>30</strong> temporary tables per second on average?</p>
<p>The slow log produced nothing helpful, even with <strong>log-queries-not-using-indexes</strong> enabled. There were a lot of queries not using indexes there, but nothing at these numbers. With:</p>
<blockquote>
<pre>oak-hook-general-log --filter-explain-temporary</pre>
</blockquote>
<p>enabled for <strong>1</strong> minute, nothing came out. Weird. Enabled for <strong>5</strong> minutes, I got one entry. Turned out a scheduled script, acting once per <strong>5</strong> minutes, was making a single complicated query involving many nested views, which accounted for some <em>hundreds</em> of temporary tables created. All of them very small, query time was very fast. There is no temporary tables problem with this server, case closed.</p>
<h4>Use case: connections</h4>
<p>A server had issues with some exceptions being thrown on the client side. There was a large number of new connections created per second although the client was using a connection pool. Suspecting the pool didn't work well, I issued:</p>
<blockquote>
<pre>oak-hook-general-log --filter-connect</pre>
</blockquote>
<p>The pool was working well, all right. No entries for that client were recorder in <strong>1</strong> minute of testing. However, it turned out some old script was flooding the MySQL server with requests, every second. The log showed root@somehost, and sure enough, the script was disabled. Exceptions were due to another reason; it was good to eliminate a suspect.</p>
<p>Some of the tool's use case is relatively easy to solve with tail, grep &amp; awk; others are not. I am using it more and more often, and find it to make significant shortcuts in tracking down queries.</p>
<h4>Get it</h4>
<p>Download the tool as part of <em>openark kit</em>: access the <a href="http://code.google.com/p/openarkkit/">openark kit project page</a>.</p>
<p>Or get the <a href="http://openarkkit.googlecode.com/svn/trunk/openarkkit/src/oak/oak-hook-general-log.py">source code</a> directly.</p>
<p>Feedback is most welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/oak-hook-general-log-your-poor-mans-query-analyzer/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>openark-kit (rev. 170): new tools, new functionality</title>
		<link>http://code.openark.org/blog/mysql/openark-kit-rev-170-new-tools-new-functionality</link>
		<comments>http://code.openark.org/blog/mysql/openark-kit-rev-170-new-tools-new-functionality#comments</comments>
		<pubDate>Wed, 15 Dec 2010 06:31:24 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Replication]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=3124</guid>
		<description><![CDATA[I'm pleased to announce a new release of the openark kit. There's a lot of new functionality inside; following is a brief overview. The openark kit is a set of utilities for MySQL. They solve everyday maintenance tasks, which may be complicated or time consuming to work by hand. It's been a while since the [...]]]></description>
			<content:encoded><![CDATA[<p>I'm pleased to announce a new release of the <a href="http://code.openark.org/forge/openark-kit">openark kit</a>. There's a lot of new functionality inside; following is a brief overview.</p>
<p>The <em>openark kit</em> is a set of utilities for MySQL. They  solve everyday maintenance tasks, which may be complicated or time  consuming to work by hand.</p>
<p>It's been a while since the last announced release. Most of my attention was on <a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a>, building new features, writing documentation etc. However my own use of <em>openark kit</em> has only increased in the past few months, and there's new useful solutions to common problems that have been developed.</p>
<p>I've used and improved many tools over this time, but doing the final cut, along with proper documentation, took some time. Anyway, here are the highlights:</p>
<h4>New tool: oak-hook-general-log</h4>
<p><em>oak-hook-general-log</em> hooks up a MySQL server and dumps the general log based on filtering rules, applying to query role or execution plan. It is possible to only dump connect/disconnect entries, queries which make a full table scan, or use temporary tables, or scan more than X number of rows, or...</p>
<p>I'll write more on this tool shortly.</p>
<h4>New tool: oak-prepare-shutdown</h4>
<p>This tool makes for an orderly and faster shutdown by safely stopping replication, and flushing InnoDB pages to disk prior to shutting down (keeping server available for connections even while attempting to flush dirty pages to disk). A typical use case would be:</p>
<blockquote>
<pre>oak-prepare-shutdown --user=root --ask-pass --socket=/tmp/mysql.sock &amp;&amp; /etc/init.d/mysql stop</pre>
</blockquote>
<h4>New tool: oak-repeat query</h4>
<p><em>oak-repeat-query</em> repeats executing a given query until some condition holds. The condition can be:</p>
<ul>
<li>Number of given iterations has been reached</li>
<li>Given time has elapsed</li>
<li>No rows have been affected by query</li>
</ul>
<p>The tool comes in handy for cleanup jobs, warming up caches, etc.<span id="more-3124"></span></p>
<h4>New tool: oak-get-slave-lag</h4>
<p>This simple tool just returns the number of seconds a slave is behind master. But it also returns with an appropriate exit code, based on a given threshold: <strong>0</strong> when lag is good, <strong>1</strong> (error exit code) when lag is too great or slave fails to replicate.</p>
<p>This tool has been used by 3rd party applications, such as a load balancer, to determine whether a slave should be accessed.</p>
<h4>Updated tool: oak-chunk-update</h4>
<p>This extremely useful utility breaks down very long queries into smaller chunks. These could be queries which should affect a huge amount of rows, or queries which cannot utilize an index.</p>
<p>Updates to the tool include limiting the range of rows the tool scans, by specifying start and stop position (either by providing constant values or by SELECT query). Also added is auto-termination when no rows are found to be affected. Last, it is possible to override INFORMATION_SCHEMA lookup by explicitly specifying chunking key.</p>
<p>This tool works great for your daily/weekly/monthly batch jobs; in creating DWH tables; populating new columns; purging old entries; clearing data based on non-indexed values; generating summary tables; and more.</p>
<h4>Frozen tool: oak-apply-ri</h4>
<p>I haven't been using this tool for a while. The main work down by this tool can be done with <em>oak-chunk-update</em>. There are some additional safety checks <em>oak-apply-ri</em> provides; I'm thinking over if they justify the tool's existence.</p>
<h4>Frozen tool: oak-online-alter-table</h4>
<p>With the appearance of Facebook’s <a href="http://www.facebook.com/note.php?note_id=430801045932">Online Schema Change</a> (OSC) tool, which derives from <em>oak-online-alter-table</em>, I'm not sure I will continue developing the tool. I intend to wait for general feedback on OSC before making a decision.</p>
<h4>Documentation</h4>
<p><a href="http://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/introduction.html">Documentation</a> is now part of <em>openark kit</em>'s SVN repository.</p>
<h4>Download</h4>
<p>The <em>openark kit</em> project is currently hosted by Google Code.  Downloads are available at the Google Code <a href="http://code.google.com/p/openarkkit/">openark kit project page</a>.</p>
<p>Downloads are available in the following packaging formats:</p>
<ul>
<li><strong>.deb</strong> package, to be installed on <em>debian</em>, <em>ubuntu</em> and otherwise debian based distributions.</li>
<li><strong>.rpm</strong> package, architecture free (<em>noarch</em>), for RPM supporting Linux distributions such as <em>RedHat</em>, <em>Fedora</em>, <em>CentOS</em> etc.</li>
<li><strong>.tar.gz</strong> using python's distutils installer.</li>
<li><strong>source</strong>, directly retrieved from SVN or from above python package.</li>
<li>Some distribution specific <a href="http://software.opensuse.org/search?baseproject=ALL&amp;p=1&amp;q=openark-kit">RPM packages</a>, courtesy Lenz Grimmer.</li>
</ul>
<h4>Feedback</h4>
<p>Your feedback is welcome! I may not always respond promptly; and I confess that some bugs were left open for more than I would have liked them to. I hope to make for good quality of code, and bug reporting is one major factor you can control.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/openark-kit-rev-170-new-tools-new-functionality/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>EXPLAIN: missing db info</title>
		<link>http://code.openark.org/blog/mysql/explain-missing-db-info</link>
		<comments>http://code.openark.org/blog/mysql/explain-missing-db-info#comments</comments>
		<pubDate>Tue, 11 May 2010 04:57:02 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[Execution plan]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=2368</guid>
		<description><![CDATA[I'm further developing a general log hook, which can stream queries from the general log. A particular direction I'm taking is to filter queries by their type of actions. For example, the tool (oak-hook-general-log) can be instructed to only stream out those queries which involve creation of a temporary table; or those which cause for [...]]]></description>
			<content:encoded><![CDATA[<p>I'm further developing a general log hook, which can stream queries from the general log.</p>
<p>A particular direction I'm taking is to filter queries by their type of actions. For example, the tool (<a href="http://code.google.com/p/openarkkit/source/browse/trunk/openarkkit/src/oak/oak-hook-general-log.py">oak-hook-general-log</a>) can be instructed to only stream out those queries which involve creation of a temporary table; or those which cause for a filesort, or full index scan, etc.</p>
<p>This is done by evaluating of query execution plans on the fly. I suspect the <a href="http://www.mysql.com/why-mysql/white-papers/mysql_wp_queryanalyzer.php">MySQL query analyzer</a> roughly does the same (as a small part of what it does).</p>
<p>It's almost nothing one cannot do with sed/awk. However, I bumped into a couple of problems:</p>
<ol>
<li>The general log (and the <strong>mysql.general_log table</strong>, in  particular) does not indicate the particular database one is using for the query. Since slow log does indicate this data, I <a href="http://bugs.mysql.com/bug.php?id=52554">filed a bug</a> on this. I currently solve this by crossing connection id with the process list, where the current database is listed. It's shaky, but mostly works.</li>
<li>Just realized: there's no DB info in the <strong>EXPLAIN</strong> output! It's weird, since I've been EXPLAINing queries for years now. But I've always had the advantage of <em>knowing</em> the schema used: either because I was manually executing the query on a known schema, or <a href="http://www.maatkit.org/doc/mk-query-digest.html">mk-query-digest</a> was kind enough to let me know.</li>
</ol>
<p><span id="more-2368"></span>For example, look at the following imaginary query, involving both the <strong>world</strong> and <strong>sakila</strong> databases:</p>
<blockquote>
<pre>mysql&gt; use test;
Database changed
mysql&gt; EXPLAIN SELECT * FROM world.Country JOIN sakila.city WHERE Country.Capital = city.city_id;
+----+-------------+---------+--------+---------------+---------+---------+-----------------------+------+-------------+
| id | select_type | table   | type   | possible_keys | key     | key_len | ref                   | rows | Extra       |
+----+-------------+---------+--------+---------------+---------+---------+-----------------------+------+-------------+
|  1 | SIMPLE      | Country | ALL    | NULL          | NULL    | NULL    | NULL                  |  239 |             |
|  1 | SIMPLE      | city    | eq_ref | PRIMARY       | PRIMARY | 2       | world.Country.Capital |    1 | Using where |
+----+-------------+---------+--------+---------------+---------+---------+-----------------------+------+-------------+
2 rows in set (0.00 sec)
</pre>
</blockquote>
<p>The query is imaginary, since the tables don't actually have anything in common. But look at the <strong>EXPLAIN</strong> result: can you tell where <strong>city</strong> came from? <strong>Country</strong> can somehow be parsed from the <strong>ref</strong> column, but no help on <strong>city</strong>.</p>
<p>Moreover, table aliases show on the <strong>EXPLAIN</strong> plan (which is good), but with no reference to the original table.</p>
<p>So, is it back to parsing of the SQL query? I'm <span style="text-decoration: line-through;">lazy</span> reluctant to do that. It's error prone, and one needs to implement, or use, a good parser, which also accepts MySQL dialect. Haven't looked into this yet.</p>
<p>I'm currently at a standstill with regard to automated query execution plan evaluation where database cannot be determined.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/explain-missing-db-info/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Static charts vs. interactive charts</title>
		<link>http://code.openark.org/blog/mysql/static-charts-vs-interactive-charts</link>
		<comments>http://code.openark.org/blog/mysql/static-charts-vs-interactive-charts#comments</comments>
		<pubDate>Tue, 02 Mar 2010 13:28:08 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[Graphs]]></category>
		<category><![CDATA[Monitoring]]></category>
		<category><![CDATA[mycheckpoint]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=2027</guid>
		<description><![CDATA[I'm having my usual fun with charts. Working on mycheckpoint, I've generated monitoring charts using the Google Chars API. But I've also had chance to experiment and deploy interactive charts, JavaScript based. In particular, I used and tweaked dygraphs. I'd like to note some differences in using charts of both kinds. And I think it [...]]]></description>
			<content:encoded><![CDATA[<p>I'm having my usual fun with charts. Working on <a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a>, I've generated monitoring charts using the <a href="http://code.google.com/apis/chart/image_charts.html">Google Chars API</a>. But I've also had chance to experiment and deploy interactive charts, JavaScript based. In particular, I used and tweaked <a href="http://www.danvk.org/dygraphs/">dygraphs</a>.</p>
<p>I'd like to note some differences in using charts of both kinds. And I think it makes a very big difference.</p>
<h4>Static charts</h4>
<p>I'll call any image-based chart by "static chart". It's just a static image. Example of such charts are those generated by Google Image Charts (they now also have new, interactive charts), or <a href="http://oss.oetiker.ch/rrdtool/index.en.html">RRDtool</a>. Show below is an example of a static chart; in this example, generated by Google:<span id="more-2027"></span></p>
<blockquote>
<pre><img class="alignnone" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=808080,12&amp;chtt=Dec+4,+15:00++-++Dec+5,+15:00&amp;chf=c,s,ffffff&amp;chdl=com_select_psec|com_insert_psec|com_delete_psec|com_update_psec|com_replace_psec&amp;chdlp=b&amp;chco=ff8c00,4682b4,9acd32,dc143c,9932cc&amp;chd=s:zpvxszxsxur11p1xt10wyxzuyv6xw4yx3x041x2zz6zvz7y91x23z4niqkkmojllkhknhlgnmimohilkkqgkkmnmhlljinjmnhmo________________imlnpmkukopmnpjsojnrrlrqnpprs,iZagVcgWXaZdjVbgSbhYdXZXZcbcXZbcadabccabbZaaZeabdYbbZXceWUXaXYXSXVXaSSZUUXWYUUXbTYUUVabWWVZZVYaWZZYa________________ZYbVcXWdYWZcXaYaYWXYfZcdaVZaZ,MNNNNNONLKOMPNNMNNOPMNNLMQNOMMMNMNNNNRONNOPMNQMPONPOLMTNKJKMKKJILKILJJJLIIKUMHJJIIHHHKJIIHIIIHJHIIJM________________NOMLMMLOPOPKLKKNPKMMNMOPQNNOL,NIIMHKOIHKIKOHKMGKNJKIJIKMKLJJMKIKJKLLJLLJLLKMLJLJKKKIIVIIJLJKJHJIKLIHMIIKIKIIKLHKIIJLKIJJKKIJKIKKJK________________IIKILJJLKIKKHJJJJIJJMIKLKGJKK,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________AAAAAAAAAAAAAAAAAAAAAAAAAAAAA&amp;chxt=x,y&amp;chxr=1,0,136.620000&amp;chxl=0:||16:00||+||20:00||+||00:00||+||04:00||+||08:00||+||12:00||+||&amp;chxs=0,505050,10,0,lt&amp;chg=4.17,25,1,2,0.00,0&amp;chxp=0,0.00,4.17,8.34,12.51,16.68,20.85,25.02,29.19,33.36,37.53,41.70,45.87,50.04,54.21,58.38,62.55,66.72,70.89,75.06,79.23,83.40,87.57,91.74,95.91,100.08" alt="" width="400" height="200" /></pre>
</blockquote>
<h4>Pros and cons of static charts</h4>
<p>Pros</p>
<ul>
<li>Images can be viewed on any graphical platform. Browsers, email clients, cell phones, whatever.</li>
<li>Self contained: chart image, legend, scales: all in one image.</li>
<li>As such, easy to move around.</li>
<li>Are safe to use.</li>
</ul>
<p>Cons</p>
<ul>
<li>Images are fuzzy. Is the <strong>com_replace_psec</strong> really 0? Maybe it's 0.1? A larger value can make lower values hard to tell.</li>
<li>Images are inaccurate: the colors can lie. The red and green lines showing are hard to tell apart. The red is painted above the green. Data gets "lost".</li>
<li>They do not zoom (one needs to regenerate larger image)</li>
<li>Unless encoded with base64, HTML pages which include images need to link outside.</li>
<li>In the particular case of Google Charts, one is limited to 2K length URL. Trust me, it's a big limitation! (PS, Google now support POST method to allow for up to 16K. But... it's a POST method...)</li>
<li>In the particular case of Google Charts, one must have an internet connection.</li>
<li>In the particular case of Google Charts, one must submit data to Google.</li>
</ul>
<h4>Interactive charts</h4>
<p>Interactive charts are those which react to your commands. These are either JavaScript or Flash based, mostly. They allow for really nice features. Take the following chart as an example: try and <strong>move over with your mouse</strong>; or <strong>select sections to zoom in</strong>.</p>
<p><script src="http://code.openark.org/blog/wp-content/uploads/2010/03/dygraph-combined.js" type="text/javascript"></script><br />
<!--[if IE]><script src="http://code.openark.org/blog/wp-content/uploads/2010/03/excanvas-min.js"></script>< ![endif]--></p>
<blockquote>
<pre>
<h4>DML</h4>
<div id="graphDiv_DML" class="graphdiv" style="width: 400px; height: 160px;">[graphDiv]</div>
<div id="labelsDiv_DML" class="legend">[labelsDiv]</div>
</pre>
</blockquote>
<p><script type="text/javascript">// < ![CDATA[
// < ![CDATA[
 g_DML = new Dygraph( document.getElementById("graphDiv_DML"),                         "Date,com_select_psec,com_insert_psec,com_delete_psec,com_update_psec,com_replace_psec\n2009-12-04 15:00:00,113.28,76.54,26.14,29.54,0.00\n2009-12-04 15:10:00,91.51,55.74,30.07,18.13,0.00\n2009-12-04 15:20:00,104.98,57.75,28.26,18.24,0.00\n2009-12-04 15:30:00,110.64,72.17,30.17,27.58,0.00\n2009-12-04 15:40:00,97.79,46.27,29.27,15.91,0.00\n2009-12-04 15:50:00,114.35,61.85,29.55,22.45,0.00\n2009-12-04 16:00:00,110.82,72.38,30.67,30.70,0.00\n2009-12-04 16:10:00,99.05,49.70,29.35,18.56,0.00\n2009-12-04 16:20:00,109.68,50.87,25.74,16.55,0.00\n2009-12-04 16:30:00,103.92,58.70,22.09,22.58,0.00\n2009-12-04 16:40:00,97.24,56.29,31.71,18.78,0.00\n2009-12-04 16:50:00,119.25,65.72,27.80,22.56,0.00\n2009-12-04 17:00:00,118.31,78.34,34.18,30.43,0.00\n2009-12-04 17:10:00,91.06,47.59,29.66,16.60,0.00\n2009-12-04 17:20:00,117.81,59.82,28.94,21.40,0.00\n2009-12-04 17:30:00,109.79,71.37,27.62,27.64,0.00\n2009-12-04 17:40:00,101.07,40.51,29.57,14.18,0.00\n2009-12-04 17:50:00,117.66,61.18,28.31,22.44,0.00\n2009-12-04 18:00:00,115.48,72.82,32.12,28.74,0.00\n2009-12-04 18:10:00,106.51,54.34,32.96,20.37,0.00\n2009-12-04 18:20:00,111.34,65.11,27.60,22.60,0.00\n2009-12-04 18:30:00,109.66,52.25,29.47,18.47,0.00\n2009-12-04 18:40:00,113.63,55.16,28.67,19.98,0.00\n2009-12-04 18:50:00,103.72,51.86,24.67,18.08,0.00\n2009-12-04 19:00:00,111.27,55.78,26.66,22.62,0.00\n2009-12-04 19:10:00,105.73,63.16,35.37,25.88,0.00\n2009-12-04 19:20:00,130.50,60.07,29.82,22.99,0.00\n2009-12-04 19:30:00,110.41,62.64,30.35,24.46,0.00\n2009-12-04 19:40:00,107.05,52.04,27.15,19.22,0.00\n2009-12-04 19:50:00,126.11,57.06,27.12,19.34,0.00\n2009-12-04 20:00:00,111.36,61.40,26.13,25.96,0.00\n2009-12-04 20:10:00,108.82,61.97,29.52,23.49,0.00\n2009-12-04 20:20:00,122.57,59.28,26.03,18.48,0.00\n2009-12-04 20:30:00,109.35,65.42,29.21,23.13,0.00\n2009-12-04 20:40:00,117.19,57.69,28.01,19.24,0.00\n2009-12-04 20:50:00,125.03,61.15,28.95,21.74,0.00\n2009-12-04 21:00:00,118.31,63.11,29.66,23.99,0.00\n2009-12-04 21:10:00,109.98,62.24,38.77,24.02,0.00\n2009-12-04 21:20:00,121.28,57.78,30.48,20.26,0.00\n2009-12-04 21:30:00,113.89,59.62,29.77,23.72,0.00\n2009-12-04 21:40:00,113.93,60.42,29.35,24.71,0.00\n2009-12-04 21:50:00,130.36,55.68,31.94,21.16,0.00\n2009-12-04 22:00:00,114.11,58.93,32.62,24.41,0.00\n2009-12-04 22:10:00,105.52,58.58,26.04,24.47,0.00\n2009-12-04 22:20:00,113.52,57.04,29.26,22.28,0.00\n2009-12-04 22:30:00,132.64,66.22,34.87,26.82,0.00\n2009-12-04 22:40:00,112.08,59.19,27.16,23.73,0.00\n2009-12-04 22:50:00,136.62,59.74,33.41,20.04,0.00\n2009-12-04 23:00:00,119.58,65.67,31.40,24.40,0.00\n2009-12-04 23:10:00,109.12,53.74,28.38,19.60,0.00\n2009-12-04 23:20:00,121.52,60.03,33.16,22.38,0.00\n2009-12-04 23:30:00,123.33,59.59,31.09,22.51,0.00\n2009-12-04 23:40:00,114.75,56.82,25.53,23.43,0.00\n2009-12-04 23:50:00,124.92,51.26,27.86,19.03,0.00\n2009-12-05 00:00:00,88.23,63.21,41.50,18.59,0.00\n2009-12-05 00:10:00,75.10,66.62,29.94,48.01,0.00\n2009-12-05 00:20:00,94.85,49.27,22.05,18.66,0.00\n2009-12-05 00:30:00,80.27,45.21,20.56,17.55,0.00\n2009-12-05 00:40:00,80.96,52.03,21.66,21.14,0.00\n2009-12-05 00:50:00,85.21,57.68,26.57,23.58,0.00\n2009-12-05 01:00:00,88.66,52.56,21.75,20.94,0.00\n2009-12-05 01:10:00,78.66,53.26,22.89,22.36,0.00\n2009-12-05 01:20:00,83.80,50.74,20.65,19.49,0.00\n2009-12-05 01:30:00,82.70,39.99,17.23,15.86,0.00\n2009-12-05 01:40:00,79.66,52.35,23.55,20.94,0.00\n2009-12-05 01:50:00,74.56,47.64,23.05,18.97,0.00\n2009-12-05 02:00:00,81.25,51.35,17.94,21.61,0.00\n2009-12-05 02:10:00,86.83,58.48,25.03,24.95,0.00\n2009-12-05 02:20:00,73.31,41.39,21.09,17.56,0.00\n2009-12-05 02:30:00,82.31,39.70,19.84,16.74,0.00\n2009-12-05 02:40:00,71.19,55.84,19.05,25.97,0.00\n2009-12-05 02:50:00,88.00,44.13,25.32,17.74,0.00\n2009-12-05 03:00:00,84.54,44.78,18.42,18.78,0.00\n2009-12-05 03:10:00,76.92,50.57,17.91,21.81,0.00\n2009-12-05 03:20:00,84.45,49.12,21.54,18.58,0.00\n2009-12-05 03:30:00,89.52,54.20,45.41,22.39,0.00\n2009-12-05 03:40:00,74.15,44.67,26.54,18.04,0.00\n2009-12-05 03:50:00,76.32,44.36,15.02,18.39,0.00\n2009-12-05 04:00:00,83.90,52.30,19.50,22.39,0.00\n2009-12-05 04:10:00,80.26,61.12,20.66,25.68,0.00\n2009-12-05 04:20:00,80.95,42.11,16.95,14.84,0.00\n2009-12-05 04:30:00,93.01,53.36,17.91,21.94,0.00\n2009-12-05 04:40:00,72.70,45.22,16.63,18.16,0.00\n2009-12-05 04:50:00,81.22,44.73,15.41,18.54,0.00\n2009-12-05 05:00:00,80.02,46.60,16.07,21.04,0.00\n2009-12-05 05:10:00,84.33,57.86,21.77,24.71,0.00\n2009-12-05 05:20:00,87.48,60.54,19.66,22.95,0.00\n2009-12-05 05:30:00,86.19,48.62,18.47,17.51,0.00\n2009-12-05 05:40:00,72.92,50.10,18.46,21.00,0.00\n2009-12-05 05:50:00,81.79,48.14,15.75,19.36,0.00\n2009-12-05 06:00:00,83.11,55.70,17.15,23.02,0.00\n2009-12-05 06:10:00,77.98,55.89,18.36,23.16,0.00\n2009-12-05 06:20:00,77.05,45.96,18.06,17.27,0.00\n2009-12-05 06:30:00,87.58,53.76,15.56,20.79,0.00\n2009-12-05 06:40:00,79.33,58.86,21.02,22.84,0.00\n2009-12-05 06:50:00,85.33,49.99,16.23,18.82,0.00\n2009-12-05 07:00:00,87.54,56.70,17.96,23.31,0.00\n2009-12-05 07:10:00,73.33,56.51,17.57,21.74,0.00\n2009-12-05 07:20:00,84.02,52.77,21.21,20.80,0.00\n2009-12-05 07:30:00,88.86,58.34,27.45,23.10,0.00\n2009-12-05 07:40:00,,,,,\n2009-12-05 07:50:00,,,,,\n2009-12-05 08:00:00,,,,,\n2009-12-05 08:10:00,,,,,\n2009-12-05 08:20:00,,,,,\n2009-12-05 08:30:00,,,,,\n2009-12-05 08:40:00,,,,,\n2009-12-05 08:50:00,,,,,\n2009-12-05 09:00:00,,,,,\n2009-12-05 09:10:00,,,,,\n2009-12-05 09:20:00,,,,,\n2009-12-05 09:30:00,,,,,\n2009-12-05 09:40:00,,,,,\n2009-12-05 09:50:00,,,,,\n2009-12-05 10:00:00,,,,,\n2009-12-05 10:10:00,,,,,\n2009-12-05 10:20:00,77.11,55.87,29.31,18.09,0.00\n2009-12-05 10:30:00,85.31,53.70,31.03,18.46,0.00\n2009-12-05 10:40:00,82.72,61.32,26.30,22.98,0.00\n2009-12-05 10:50:00,87.28,46.53,25.04,18.04,0.00\n2009-12-05 11:00:00,92.07,62.62,27.09,25.14,0.00\n2009-12-05 11:10:00,84.59,50.42,25.97,19.96,0.00\n2009-12-05 11:20:00,80.34,49.64,25.75,20.31,0.00\n2009-12-05 11:30:00,103.61,64.36,31.79,24.71,0.00\n2009-12-05 11:40:00,80.03,54.33,33.83,22.37,0.00\n2009-12-05 11:50:00,90.42,48.24,31.26,18.43,0.00\n2009-12-05 12:00:00,92.51,56.34,33.53,22.45,0.00\n2009-12-05 12:10:00,84.34,62.26,22.66,23.31,0.00\n2009-12-05 12:20:00,86.24,51.96,25.69,16.02,0.00\n2009-12-05 12:30:00,92.08,58.61,23.16,19.34,0.00\n2009-12-05 12:40:00,78.48,53.33,22.72,19.51,0.00\n2009-12-05 12:50:00,97.85,57.71,29.80,20.19,0.00\n2009-12-05 13:00:00,89.23,54.84,34.62,20.93,0.00\n2009-12-05 13:10:00,78.92,50.02,22.47,18.19,0.00\n2009-12-05 13:20:00,87.24,50.92,26.37,19.38,0.00\n2009-12-05 13:30:00,96.29,54.78,27.13,20.04,0.00\n2009-12-05 13:40:00,96.39,69.48,30.21,27.19,0.00\n2009-12-05 13:50:00,83.21,55.13,26.48,18.00,0.00\n2009-12-05 14:00:00,97.00,63.61,30.89,22.23,0.00\n2009-12-05 14:10:00,94.65,65.33,33.51,25.04,0.00\n2009-12-05 14:20:00,86.94,58.14,36.10,22.07,0.00\n2009-12-05 14:30:00,91.91,47.25,28.41,14.45,0.00\n2009-12-05 14:40:00,92.55,55.73,29.59,20.69,0.00\n2009-12-05 14:50:00,97.35,58.90,31.63,22.22,0.00\n2009-12-05 15:00:00,97.91,56.09,23.80,21.68,0.00\n",                         { chartDiv:  document.getElementById("chartDiv_DML"), labelsDiv: document.getElementById("labelsDiv_DML") } ); g_DML.resize(400,160);
// ]]&gt;</script></p>
<p>The above chart is generated with <em>dygraphs</em>. Since it is embedded within my WordPress page, the layout is affected by that of my theme. Take a look at this <a href="http://code.openark.org/blog/wp-content/uploads/2010/03/mycheckpoint_interactive_demo.html"><strong>example page</strong></a> to see similar charts outside this blog site (Internet Explorer users: Maxmimize/minimize button will not work well for now. And, may I suggest <a href="http://www.mozilla.com/en-US/firefox">Mozilla Firefox</a>?)<a href="http://code.openark.org/blog/wp-content/uploads/2010/03/mycheckpoint_interactive_demo.html"></a></p>
<h4>Pros and cons of interactive charts</h4>
<p>Pros</p>
<ul>
<li>Can present you with exact values. No more doubt about the <strong>com_replace_psec</strong> values.</li>
<li>Can allow for zoom in, zoom out.</li>
</ul>
<p>Cons</p>
<ul>
<li>Need supporting platform. The above cannot be viewed by non-JavaScript browsers (cell phones, etc.)</li>
<li>Browser support is also an issue with JavaScript.</li>
<li>Emailing such report will result in mail blocking in many companies: mail filters will not allow for JavaScript code to pass.</li>
<li>Charts are not necessarily self-contained, in terms of the chart entity With Flash charts (e.g. Fusion Charts) this works. But in the above, the legend and scales are outside the image. As such, they cannot be just moved around.</li>
<li>HTML pages which include such charts <em>can be</em> self contained. The HTML page can include all the JavaScript dependencies, in addition to the chart generating code. Flash based charts cannot be self contained.</li>
</ul>
<h4>Summary</h4>
<p>Interactive charts are cool!</p>
<p>I'm now integrating <a href="http://www.danvk.org/dygraphs/">dygraphs</a> into <em>mycheckpoint</em> (How nice it is to work with BSD &amp; MIT licenses!). Though I may later switch to <a href="http://code.google.com/p/flot/">flot</a>, interactive charts will be the next standard charting way in <em>mycheckpoint</em>. I will continue supporting static Google Charts, as follows from the above pros and cons list.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/static-charts-vs-interactive-charts/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Performance analysis with mycheckpoint</title>
		<link>http://code.openark.org/blog/mysql/performance-analysis-with-mycheckpoint</link>
		<comments>http://code.openark.org/blog/mysql/performance-analysis-with-mycheckpoint#comments</comments>
		<pubDate>Thu, 12 Nov 2009 10:47:00 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[Monitoring]]></category>
		<category><![CDATA[mycheckpoint]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=1568</guid>
		<description><![CDATA[mycheckpoint (see announcement) allows for both graph presentation and quick SQL access to monitored &#38; analyzed data. I'd like to show the power of combining them both. InnoDB performance Taking a look at one of the most important InnoDB metrics: the read hit ratio (we could get the same graph by looking at the HTML [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a> (see <a href="http://code.openark.org/blog/mysql/announcing-mycheckpoint-lightweight-sql-oriented-monitoring-for-mysql">announcement</a>) allows for both graph presentation and quick SQL access to monitored &amp; analyzed data. I'd like to show the power of combining them both.</p>
<h4>InnoDB performance</h4>
<p>Taking a look at one of the most important InnoDB metrics: the read hit ratio (we could get the same graph by looking at the <a href="http://code.openark.org/forge/mycheckpoint/documentation/generating-html-reports">HTML report</a>):</p>
<blockquote>
<pre>SELECT innodb_read_hit_percent FROM sv_report_chart_sample \G
*************************** 1. row ***************************
innodb_read_hit_percent: http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+10,+11:40++-++Nov+11,+08:55+(0+days,+21+hours)&amp;chdl=innodb_read_hit_percent&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:400664366P6674y7176677677u467773y64ux166666764366646y616666666666644444434444s6u4S331444404433341334433646777666666074736777r1777767764776666F667777617777777777777777yaRi776776mlf667676xgx776766rou67767777u37797777x76676776u6A737464y67467761777666643u66446&amp;chxt=x,y&amp;chxr=1,99.60,100.00&amp;chxl=0:||Nov+10,+15:55|Nov+10,+20:10|Nov+11,+00:25|Nov+11,+04:40|&amp;chxs=0,505050,10</pre>
</blockquote>
<blockquote>
<pre><img class="alignnone" title="innodb_read_hit_percent" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+10,+11:40++-++Nov+11,+08:55+(0+days,+21+hours)&amp;chdl=innodb_read_hit_percent&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:400664366P6674y7176677677u467773y64ux166666764366646y616666666666644444434444s6u4S331444404433341334433646777666666074736777r1777767764776666F667777617777777777777777yaRi776776mlf667676xgx776766rou67767777u37797777x76676776u6A737464y67467761777666643u66446&amp;chxt=x,y&amp;chxr=1,99.60,100.00&amp;chxl=0:||Nov+10,+15:55|Nov+10,+20:10|Nov+11,+00:25|Nov+11,+04:40|&amp;chxs=0,505050,10" alt="" width="400" height="200" /></pre>
</blockquote>
<p>We see that read hit is usually high, but occasionally drops low, down to 99.7, or even 99.6. But it seems like most of the time we are above 99.95% read hit ratio. It's hard to tell about 99.98%.</p>
<h4>Can we know for sure?</h4>
<p>We can stress our eyes, yet be certain of little. It's best if we just query for the metrics! <em>mycheckpoint</em> provides with all data, accessible by simple SQL queries:<span id="more-1568"></span></p>
<blockquote>
<pre>SELECT SUM(innodb_read_hit_percent &gt; 99.95)/count(*)
  FROM sv_report_sample;
+-----------------------------------------------+
| SUM(innodb_read_hit_percent &gt; 99.95)/count(*) |
+-----------------------------------------------+
|                                        0.7844 |
+-----------------------------------------------+</pre>
</blockquote>
<p>Yes, most of the time we're above 99.95% read hit ratio: but not too often!</p>
<p>I'm more interested in seeing how much time my server's above 99.98% read hit:</p>
<blockquote>
<pre>SELECT SUM(innodb_read_hit_percent &gt; 99.98)/count(*)
  FROM sv_report_sample;
+-----------------------------------------------+
| SUM(innodb_read_hit_percent &gt; 99.98)/count(*) |
+-----------------------------------------------+
|                                        0.3554 |
+-----------------------------------------------+</pre>
</blockquote>
<p>We can see the server only has 99.98% read hit percent 35% of the time. Need to work on that!</p>
<h4>Disk activity</h4>
<p>Lower read hit percent means higher number of disk reads; that much is obvious. The first two following graphs present this obvious connection. But the third graph tells us another fact: with increased disk I/O, we can expect more (and longer) locks.</p>
<p>Again, this should be very intuitive, when thinking about it this way. The problem sometimes arises when we try to analyze it the other way round: "Hey! InnoDB has a lot of locks! What are we going to do about it?". Many times, people will look for answers in their <em>transactions</em>, their <em>Isolation Level</em>, their <em>LOCK IN SHARE MODE</em> clauses. But the simple answer can be: "There's a lot of I/O, so everything has to wait; therefore we increase the probability for locks; therefore there's more locks".</p>
<p>The answer, then, is to reduce I/O. The usual stuff: slow queries; indexing; ... and, yes, perhaps transactions or tuning.</p>
<p>The charts below make it quite clear that we have an issue of excessive reads -&gt; less read hit -&gt; increased I/O -&gt; more locks.</p>
<blockquote>
<pre><img class="alignnone" title="DML" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Oct+31,+17:00++-++Nov+11,+08:00+(10+days,+15+hours)&amp;chdl=com_select_psec|com_insert_psec|com_delete_psec|com_update_psec|com_replace_psec&amp;chdlp=b&amp;chco=ff8c00,4682b4,9acd32,dc143c,9932cc&amp;chd=s:IJJJJJKHGHGHGHHHHHIIIJJJKKKLKLLIHHHIHIHIIIJJJJJKKKLLLLMIHHHHHHHIIIIIJJKKKLLLLMMIHIIIIIIIIIIJJJJKKLLLLMMIHHHIHIHIIIJJJJJKKLKLLLLIHHHIHIHIIIIJIJJJJKKKKKKHHHHHHHHHHHHIIIIJIJJJJJKHHHHHHHHHHIIJJNKLLKKLLLMSMHHIHHHIOSae9RNPJIIJJJKHGGGHGGHHHHHJJKJLKLLLMKMJHIIIIIII,EEEEEEEFEEEEEEEFEFFFFFFFFFFFFFFEEFFEEEEEFFFFFFFFFFFGFFFGFFFFEEEEFFFFFFGGFGFFFFFGEFFFEEFFFFFFFFFFFFFFFFFGEEEEEEEEFFFGGFFFFGFFFFFGEEEFFEEFFEFFEEFFFFFFFEEFEEEEEEEEEEEEEEFFEEEEFEEGEEEEEEEEEFFFFFFFFFEFFFFHEEEEEEEFFFFFFFFFFEEEEFEHEFEEEEEEEEFFFGFGGFFFFFFIEEEEEEEF,CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDCCCCCCDDCCCCCCCCCCCCCCCDCCCCCCCCCCCCCCCCCCDCCCCECCBCBCCCCCCCCCCDCCCCCDCECCCCCCCCCCCCCCCCCCCDCCCDCCCCBBCCCCDCCDCCCCCCCCCECCCBBCCCCCCCCCCCCCCCCCCFCCBCCCCCCCCCCCCCCCCCCCCFCCCCBCCCCCCCDCCCCDCCDCCGCCCCCCCD,CBCCCBBCBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBCCCCCCCCCCCCCCBBBCCCCCCBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBCBBBBBBBBCBBCCCCCCCCCCCCCCCCCCCCC,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&amp;chxt=x,y&amp;chxr=1,0,680.42&amp;chxl=0:||Nov+2,+20:00|Nov+4,+23:00|Nov+7,+02:00|Nov+9,+05:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" />

<img class="alignnone" title="innodb_read_hit_percent" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Oct+31,+17:00++-++Nov+11,+08:00+(10+days,+15+hours)&amp;chdl=innodb_read_hit_percent&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:8p879mq7z1377377777z788863778839z13773877633697786888969z1379377667275377376672813167266771288716689y759121685885785236675889869232685789w63y69997989999252696878y8698878588886933368587ffpibibaTYRfVAdXjqfdmbYneRhciXYcifb6995802z56377666576877268875913278387&amp;chxt=x,y&amp;chxr=1,99.44,99.99&amp;chxl=0:||Nov+2,+20:00|Nov+4,+23:00|Nov+7,+02:00|Nov+9,+05:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" />

<img class="alignnone" title="innodb_io" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Oct+31,+17:00++-++Nov+11,+08:00+(10+days,+15+hours)&amp;chdl=innodb_buffer_pool_reads_psec|innodb_buffer_pool_pages_flushed_psec&amp;chdlp=b&amp;chco=ff8c00,4682b4&amp;chd=s:DYDDBZVEPMJEFKFGGGEOEDDDEJDECBGBONKEFJEFFFIHFCDDCECCCBECSPLECJEFGHFLDGHEDHEEEDHCMJMGFLGHFELMDCDLEFDBRDFBKIKECIDEHEDHJHFEDGCDCDFCKJKFEJFECRGHNFCCBFBECBCCLHKFBGDEDUEGBCCEEHDCDDFBJJJFEIDFwrfpthozmqqcn3g9hYjkbpqdsvhxormohorGCBHDOLNGEHEDFFGIEFDEDKFDDDGCLIJECIDE,EEEEEGEFSWUFFEGHKIHHHGGHJIHHHHGGQbTFFEFFHGGGGFFHHHGHGFFGUdYGDEGFJKIHHHLKJJJIHHHGHZQRGFGHIHIGGGHIIIGHFFFEHYPNCEFEHHIIIKKJIJHHGIFFGbSPFGJIGFGGGEFFEFEFFEEGSIUODCDFHGGFEEGGGGGGGHFFGYPNDFFGJHIJJIJIHHGFFFEHHVSLCDGIHIHGIHGGFGFFFGIJTRSMEEFFGHHIIIHJKLKHIHGHPNNMCFGE&amp;chxt=x,y&amp;chxr=1,0,151.44&amp;chxl=0:||Nov+2,+20:00|Nov+4,+23:00|Nov+7,+02:00|Nov+9,+05:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" />

<img class="alignnone" title="innodb_row_lock_waits_psec" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Oct+31,+17:00++-++Nov+11,+08:00+(10+days,+15+hours)&amp;chdl=innodb_row_lock_waits_psec&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:GWFGGYSHQJKFGJHIHIHNGHGGGKHHFFGGMMJFFKHHHKMIHGIIJGGFGFHGTNOGFJIHGJGKGJHGGGGFHFJFPIKFFJHJIFLKGGFIFGGEVEJGPILGFIGHJJHIJKGGFJGLIGKGJMSGGIGIGVGGQJGHHKHIGHFGLHMHFIFIGQGGIFGJHIEEHFHGKLJHGGGIYgTVXOaXabSUadW9gVfRSeaQbfalXeYcXTiGHIKHKEJEFFFGGGIGGGGHGKGGHGLGPJHGFJEG&amp;chxt=x,y&amp;chxr=1,0,1.42&amp;chxl=0:||Nov+2,+20:00|Nov+4,+23:00|Nov+7,+02:00|Nov+9,+05:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" /></pre>
</blockquote>
<p>By the way, the above resulted from the fact that, due to a problematic query, all slave stopped replicating. Slaves participated in read-balancing, so when they went stale, all reads were directed at the master (the monitored node).</p>
<h4>You have the metrics at your disposal</h4>
<p>Looking at the following chart:</p>
<blockquote>
<pre><img class="alignnone" title="questions" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+11,+15:15++-++Nov+12,+12:30+(0+days,+21+hours)&amp;chdl=queries_psec|questions_psec|slow_queries_psec|com_commit_psec|com_set_option_psec&amp;chdlp=b&amp;chco=ff8c00,4682b4,9acd32,dc143c,9932cc&amp;chd=s:pqpviksvvz0vuxxxjpw0mwpkkso1vhuvn0nnrtx2uisrnvoknmusomqvlyymsvpuweqslwumkomutcromzrinukvwcuzotujjto1shrtszqlu849mXenejkaZlZhcYbgciaZZegecUWhZkaYWebfaXVaecdZUZgdbSbccbcTXYeaaTYZfZeVjbnZhRdegcfYorkdmVadqenfcknkoadeuhrjcbptpkhkqkrqfjprrtmllmnqdwsusojoo0qtpwp4,abfjVQebgjaWeedkWRgcelWUcdclYUhddnaVidendUieflaUhcfkdRfefmgSjianfPkcdmfUegamfRmcfmgTgegmhQghgmgWeiepfShfhqjcqzwzfVYdbfbUXbXcYSYaYdVWUZabWTTbXeYUVZYdVTUYabYWUYbbXSWaYaYSSXZZVTVZaXZURZaWbQWZaaYWUWbaZSUadadVUcbbbTWYeabXUUcebUYbabdVUYbbdTWaaccWTddaeTWbdbgXXdci,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,MLOPJHNMNPLKNNNQJHOMNQJJMMMQLIPMNSLJPNNRNJPNNRKJPMNQNHONNRNIPPLROHQNMRNJOOMRNHRMNRNJONOROHOPOROKNPNTOIPOOTOMQUSUNJKNLOLJKMKMKIKLKMJJILLMKIIMKNJJJLKNIJJKKMKJIKLMKHJLKLKIIKKLJIJLKKKJHLLKLHJLKLKJIKLLKIJLMLMKJMMMMIJKMLLKIJMNLJKMLMMJJKLMNIKLLMMKIMMLNIKMMMOKKNMP&amp;chxt=x,y&amp;chxr=1,0,916.47&amp;chxl=0:||Nov+11,+19:30|Nov+11,+23:45|Nov+12,+04:00|Nov+12,+08:15|&amp;chxs=0,505050,10" alt="" width="400" height="200" /></pre>
</blockquote>
<p>It appears that there's no slow queries. But this may be misleading: perhaps there's just a little, that don't show due to the chart's large scale?</p>
<p>One could argue that this is the chart's fault. Perhaps there should be a distinct chart for "slow queries percent". Perhaps I'll add one. But we can't have special charts for everything. It's would be too tiresome to look at hundreds of charts.</p>
<p>Anyway, my point is: let's verify just how many slow queries we have:</p>
<blockquote>
<pre>SELECT slow_queries_psec FROM sv_hour ORDER BY id DESC;
+-------------------+
| slow_queries_psec |
+-------------------+
|              3.05 |
|              3.83 |
|              4.39 |
|              4.03 |
|              3.86 |
|              3.56 |
|              3.73 |
|              3.79 |
|              3.58 |
|              3.55 |
...
+-------------------+</pre>
</blockquote>
<p>So, between 3 and 4 slow queries per second. It doesn't look too good in this light. Checking on the percentage of slow queries (of total questions):</p>
<blockquote>
<pre>SELECT ROUND(100*slow_queries_diff/questions_diff, 1) AS slow_queries_percent
  FROM sv_hour ORDER BY id DESC LIMIT 10;</pre>
</blockquote>
<p>Or, since the above calculation is pre-defined in the reports tables:</p>
<blockquote>
<pre>SELECT slow_queries_percent FROM sv_report_hour_recent;
+----------------------+
| slow_queries_percent |
+----------------------+
|                  0.8 |
|                  1.0 |
|                  1.2 |
|                  1.2 |
|                  1.1 |
|                  1.0 |
|                  1.1 |
|                  1.1 |
|                  1.0 |
...
+----------------------+</pre>
</blockquote>
<h4>Accessible data</h4>
<p>This is what I've been trying to achieve with <em>mycheckpoint</em>. As a DBA, consultant and SQL geek I find that direct SQL access works best for me. It's like loving command line interface over GUI tools. Direct SQL gives you so much more control and information.</p>
<p>Charting is important, since it's easy to watch and get first impressions, or find extreme changes. But beware of relying on charts all the time. Scale issues, misleading human interpretation, technology limitations - all these make charts inaccurate.</p>
<p><a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a> allows for both methods, and, I believe, intuitively so.</p>
<p>&lt;/propaganda&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/performance-analysis-with-mycheckpoint/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Replication analysis with mycheckpoint</title>
		<link>http://code.openark.org/blog/mysql/replication-analysis-with-mycheckpoint</link>
		<comments>http://code.openark.org/blog/mysql/replication-analysis-with-mycheckpoint#comments</comments>
		<pubDate>Wed, 11 Nov 2009 03:50:28 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Analysis]]></category>
		<category><![CDATA[Monitoring]]></category>
		<category><![CDATA[mycheckpoint]]></category>
		<category><![CDATA[Replication]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=1529</guid>
		<description><![CDATA[I would like to show how mycehckpoint (see announcement) can be put to use for analyzing various replication metrics. Lagging slaves A slave has been monitored. Monitoring started at a time when it was way behind master (about two days lag), but it has since caught up. This can be easily verified by the following [...]]]></description>
			<content:encoded><![CDATA[<p>I would like to show how <a href="http://code.openark.org/forge/mycheckpoint">mycehckpoint</a> (see <a href="http://code.openark.org/blog/mysql/announcing-mycheckpoint-lightweight-sql-oriented-monitoring-for-mysql">announcement</a>) can be put to use for analyzing various replication metrics.</p>
<h4>Lagging slaves</h4>
<p>A slave has been monitored. Monitoring started at a time when it was way behind master (about two days lag), but it has since caught up. This can be easily verified by the following chart:</p>
<blockquote>
<pre><img class="alignnone" title="seconds_behind_master" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+08:00+(4+days,+22+hours)&amp;chdl=seconds_behind_master&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:976431zzzywutrpnliiifdbZYXVTRRRPNLJHEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&amp;chxt=x,y&amp;chxr=1,0,169811&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+08:00|Nov+9,+08:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" /></pre>
</blockquote>
<p>The above chart can be obtained by viewing the HTML report:</p>
<blockquote>
<pre>SELECT <strong>html</strong> FROM sv_report_html</pre>
</blockquote>
<p>Or by directly issuing the query:</p>
<blockquote>
<pre>mysql&gt; SELECT <strong>seconds_behind_master</strong> FROM sv_report_chart_hour\G
*************************** 1. row ***************************
seconds_behind_master: http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+08:00+(4+days,+22+hours)&amp;chdl=seconds_behind_master&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:976431zzzywutrpnliiifdbZYXVTRRRPNLJHEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&amp;chxt=x,y&amp;chxr=1,0,169811&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+08:00|Nov+9,+08:00|&amp;chxs=0,505050,10</pre>
</blockquote>
<p>This is all nice. But I'm also interested in the <em>rate</em> at which slave lag decreased. Many ignore this important metric: just how fast does your slave replicate?</p>
<h4><span id="more-1529"></span>Slave catchup speed</h4>
<p>So we're looking for the <em>slope</em> of the above graph. Luckily, the slope is nothing but the difference in <strong>seconds_behind_master</strong> divided by elapsed time. <em>mycheckpoint</em> supports the <strong>*_psec</strong> metrics for all known variables.</p>
<p>Again, we can just look at the HTML report, or we can issue:</p>
<blockquote>
<pre>mysql&gt; SELECT <strong>seconds_behind_master_psec</strong> FROM sv_report_chart_hour\G
*************************** 1. row ***************************
seconds_behind_master_psec: http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+08:00+(4+days,+22+hours)&amp;chdl=seconds_behind_master_psec&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:fbdebXU0wvOgaYXVUIutFTacefXXS4xhYRTJAKf90444444444444444444444482444444445444444444444472544444444444444444444481544444&amp;chxt=x,y&amp;chxr=1,-2.35,0.19&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+08:00|Nov+9,+08:00|&amp;chxs=0,505050,10</pre>
</blockquote>
<p>And get this chart:</p>
<blockquote>
<pre><img class="alignnone" title="seconds_behind_master_psec" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+08:00+(4+days,+22+hours)&amp;chdl=seconds_behind_master_psec&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:fbdebXU0wvOgaYXVUIutFTacefXXS4xhYRTJAKf90444444444444444444444482444444445444444444444472544444444444444444444481544444&amp;chxt=x,y&amp;chxr=1,-2.35,0.19&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+08:00|Nov+9,+08:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" /></pre>
</blockquote>
<p>The numbers show a reasonable slave catchup speed (lower is better). For example, a <strong>-1</strong> value indicates that the slave is replicating twice as fast as the master. So if we're 10 minutes behind, catch up will occur 10 minutes from now (the slave will cover for the missing 10 minutes plus the future 10 minutes by which the master will be writing). At times, replication went very fast (slope as low as <strong>-2.25</strong> on average), and at times is was very slow (<strong>-0.25</strong>).</p>
<p>But all negative numbers are good! They mean slave is faster than master. Indeed, once the slave caught up, numbers climbed to <strong>0</strong>: the slave has since been running at same speed as the master.</p>
<h4>Estimating slave catchup time</h4>
<p>When we have a lagging slave, there's nothing more interesting to known than "when will it finally catch up?". We can do the math: calculating slope, extrapolating the expected point in time where the lag drops to <strong>0</strong>; or we can just ask!</p>
<p>Let's first ask the hard way, then the human way:</p>
<p>Querying the history of estimations:</p>
<blockquote>
<pre>SELECT ts, <strong>estimated_slave_catchup_seconds</strong> FROM sv_report_hour;
+---------------------+---------------------------------+
| ts                  | estimated_slave_catchup_seconds |
+---------------------+---------------------------------+
| 2009-11-06 16:00:00 |                          142984 |
| 2009-11-06 17:00:00 |                           47988 |
| 2009-11-06 18:00:00 |                           31416 |
| 2009-11-06 19:00:00 |                           22896 |
| 2009-11-06 20:00:00 |                           20202 |
| 2009-11-06 21:00:00 |                           13062 |
| 2009-11-06 22:00:00 |                            7932 |
| 2009-11-06 23:00:00 |                            5220 |
| 2009-11-07 00:00:00 |                            2740 |
| 2009-11-07 01:00:00 |                            NULL |
| 2009-11-07 02:00:00 |                             463 |
| 2009-11-07 03:00:00 |                            NULL |
| 2009-11-07 04:00:00 |                            NULL |
| 2009-11-07 05:00:00 |                            NULL |
| 2009-11-07 06:00:00 |                            NULL |
...
+---------------------+---------------------------------+</pre>
</blockquote>
<p>(NULL occurs when slave has caught up; so nothing to estimate)</p>
<p>Had we been checking up on human reports at the time of lag, we would see something like:</p>
<blockquote>
<pre>mysql&gt; SELECT <strong>report</strong> FROM sv_report_human_hour ORDER BY ID DESC LIMIT 1\G
*************************** 1. row ***************************
report:
Report period: 2009-11-06 16:00:00 to 2009-11-06 17:00:00. Period is 60 minutes (1.00 hours)
Uptime: 100.0% (Up: 1 days, 05:34:00 hours)

...
...
...

Replication:
    Master status file number: 541, position: 825383347
    Relay log space limit: 10737418240, used: 4512632192  (42.0%)
    Seconds behind master: 47185
    <strong>Estimated time for slave to catch up: 142984 seconds (1 days, 15:43:05 hours)  ETA: 2009-11-08 07:43:05</strong></pre>
</blockquote>
<p>The human report suggested it would take more than a day and a half for replication to catch up; it also provided with ETA: '<strong></strong><strong>2009-11-08 07:43:05</strong>'.</p>
<p>As an interesting note, to issue the above report I <em>went back in time</em> and issued:</p>
<blockquote>
<pre>SELECT report FROM sv_report_human_hour <strong>WHERE ts='2009-11-06 16:00:00'</strong>\G</pre>
</blockquote>
<p>It's possible to retroactively generate report, for as long as data still exists.</p>
<h4>Checking up on relay log space</h4>
<p>Slaves are limited in relay log space. They can only accumulate as much relay logs.</p>
<p>Usually the slave SQL thread is slower than the IO thread, which means when the slave lags behind, it writes more and more relay logs, while having hard time reading them. Once it runs out of relay log space, it stops asking the master for more binary logs, and waits for relay log space to free.</p>
<p>How much relay log space should a slave have?</p>
<p>Well, if you're not worries about disk space, let it have as much as it would like to; but let's look at the implications of relay log space limit. Again, by either looking at the HTML report or by directly issuing:</p>
<blockquote>
<pre>mysql&gt; SELECT relay_log_used_mb FROM sv_report_chart_hour\G
*************************** 1. row ***************************
relay_log_used_mb: http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+09:00+(4+days,+23+hours)&amp;chdl=relay_log_space_limit_mb|relay_log_space_mb&amp;chdlp=b&amp;chco=ff8c00,4682b4&amp;chd=s:999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999,9999999999989570xytsuxursojfhcabWRSOJEGBCBCDEGBCEBDEFGBEGBDFBCEFGBCDEGBDFBDFCFACEGBCDEGBCBBDEFACEFBCEGBCDEFABCEBEDFACDEF&amp;chxt=x,y&amp;chxr=1,0,10240.10309792&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+09:00|Nov+9,+09:00|&amp;chxs=0,505050,10</pre>
</blockquote>
<p>We get:</p>
<blockquote>
<pre><img class="alignnone" title="relay_log_used_mb" src="http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+09:00+(4+days,+23+hours)&amp;chdl=relay_log_space_limit_mb|relay_log_space_mb&amp;chdlp=b&amp;chco=ff8c00,4682b4&amp;chd=s:999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999,9999999999989570xytsuxursojfhcabWRSOJEGBCBCDEGBCEBDEFGBEGBDFBCEFGBCDEGBDFBDFCFACEGBCDEGBCBBDEFACEFBCEGBCDEFABCEBEDFACDEF&amp;chxt=x,y&amp;chxr=1,0,10240.10309792&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+09:00|Nov+9,+09:00|&amp;chxs=0,505050,10" alt="" width="400" height="200" /></pre>
</blockquote>
<p>I see that 2 days lag (comparing with the above charts) will cause the relay log space to fill up. I would consider this to be OK, since I don't normally expect such lags. I can see that a one-day lag is well within relay log space. I conclude that the <strong>relay_log_space_limit</strong> server variable is properly configured in my case.</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 19px; width: 1px; height: 1px;">http://chart.apis.google.com/chart?cht=lc&amp;chs=400x200&amp;chts=303030,12&amp;chtt=Nov+5,+10:00++-++Nov+10,+08:00+(4+days,+22+hours)&amp;chdl=seconds_behind_master_psec&amp;chdlp=b&amp;chco=ff8c00&amp;chd=s:fbdebXU0wvOgaYXVUIutFTacefXXS4xhYRTJAKf90444444444444444444444482444444445444444444444472544444444444444444444481544444&amp;chxt=x,y&amp;chxr=1,-2.35,0.19&amp;chxl=0:||Nov+6,+09:00|Nov+7,+09:00|Nov+8,+08:00|Nov+9,+08:00|&amp;chxs=0,505050,10</div>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/replication-analysis-with-mycheckpoint/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

