<?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; openark kit</title>
	<atom:link href="http://code.openark.org/blog/tag/openark-kit/feed" rel="self" type="application/rss+xml" />
	<link>http://code.openark.org/blog</link>
	<description>Blog by Shlomi Noach</description>
	<lastBuildDate>Tue, 07 Sep 2010 05:53:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<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&#8217;m further developing a general log hook, which can stream queries from the general log. A particular direction I&#8217;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&#8217;m further developing a general log hook, which can stream queries from the general log.</p>
<p>A particular direction I&#8217;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&#8217;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&#8217;s shaky, but mostly works.</li>
<li>Just realized: there&#8217;s no DB info in the <strong>EXPLAIN</strong> output! It&#8217;s weird, since I&#8217;ve been EXPLAINing queries for years now. But I&#8217;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&#8217;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&#8217;m <span style="text-decoration: line-through;">lazy</span> reluctant to do that. It&#8217;s error prone, and one needs to implement, or use, a good parser, which also accepts MySQL dialect. Haven&#8217;t looked into this yet.</p>
<p>I&#8217;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>oak-hook-general-log: streaming general log</title>
		<link>http://code.openark.org/blog/mysql/oak-hook-general-log-streaming-general-log</link>
		<comments>http://code.openark.org/blog/mysql/oak-hook-general-log-streaming-general-log#comments</comments>
		<pubDate>Sun, 21 Mar 2010 08:45:58 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=2253</guid>
		<description><![CDATA[I&#8217;m seeking input on a new openark kit utility I&#8217;ve started to implement. The tool, oak-hook-general-log, will hook up to a MySQL (&#62;= 5.1) server, and stream the general log into standard output. It looks like this: bash$ python src/oak/oak-hook-general-log.py --socket=/tmp/mysql.sock --user=root 2010-03-21 10:18:42     root[root] @ localhost []       79      1       Query   SELECT COUNT(*) FROM City [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m seeking input on a new <a href="http://code.openark.org/forge/openark-kit">openark kit</a> utility I&#8217;ve started to implement.</p>
<p>The tool, <strong>oak-hook-general-log</strong>, will hook up to a MySQL (&gt;= 5.1) server, and stream the general log into standard output. It looks like this:</p>
<blockquote>
<pre>bash$ python src/oak/oak-hook-general-log.py --socket=/tmp/mysql.sock --user=root
2010-03-21 10:18:42     root[root] @ localhost []       79      1       Query   SELECT COUNT(*) FROM City
2010-03-21 10:18:48     root[root] @ localhost []       79      1       Query   DELETE FROM City WHERE id=1000
2010-03-21 10:18:54     root[root] @ localhost []       79      1       Query   SHOW PROCESSLIST
2010-03-21 10:19:06     root[root] @ localhost []       79      1       Quit
2010-03-21 10:19:07     root[root] @ localhost []       93      1       Connect root@localhost on
2010-03-21 10:19:07     root[root] @ localhost []       93      1       Query   select @@version_comment limit 1
2010-03-21 10:22:33     root[root] @ localhost []       93      1       Query   SELECT City.Name, Country.Name FROM Country JOIN City ON Country.Capit
2010-03-21 10:22:58     root[root] @ localhost []       93      1       Quit
</pre>
</blockquote>
<p>Since output is written to <strong>stdout</strong>, one can further:</p>
<blockquote>
<pre>bash$ python src/oak/oak-hook-general-log.py --socket=/tmp/mysql.sock --user=root | grep Connect
bash$ python src/oak/oak-hook-general-log.py --socket=/tmp/mysql.sock --user=root | grep webuser@webhost</pre>
</blockquote>
<p>What the tool does is to enable table logs, and periodically rotate the <strong>mysql.general_log</strong> table, read and dump its content.</p>
<p><span id="more-2253"></span>The tool:</p>
<ul>
<li>Stores and restores the original log state (general log enabled/disabled, log output).</li>
<li>Disables printing of its own queries to the general log.</li>
<li>Automatically times out (timeout configurable) so as not to enter a situation where the general log is forgotten to be turned on.</li>
<li>Can discard pre-existing data on the <strong>mysql.general_log</strong> table.</li>
<li>Will cleanup the <strong>mysql.slow_log</strong> table, if it wasn&#8217;t originally used (turning on table logs applies to both general log and slow log).</li>
</ul>
<p>What would you have the tool do further? Should it provide filtering, or should we just use <strong>grep</strong>/<strong>sed</strong>/<strong>awk</strong> for that? Any internal aggregation of data?</p>
<p>I would love to hear your thoughts. Meanwhile, <a href="http://code.google.com/p/openarkkit/source/browse/trunk/openarkkit/src/oak/oak-hook-general-log.py">view or grab the python script file</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/oak-hook-general-log-streaming-general-log/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>mk-schema-change? Check out ideas from oak-online-alter-table</title>
		<link>http://code.openark.org/blog/mysql/mk-schema-change-check-out-ideas-from-oak-online-alter-table</link>
		<comments>http://code.openark.org/blog/mysql/mk-schema-change-check-out-ideas-from-oak-online-alter-table#comments</comments>
		<pubDate>Wed, 10 Mar 2010 18:28:29 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[Schema]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=2144</guid>
		<description><![CDATA[In response to Mark Callaghan&#8217;s post mk-schema-change. I apologize for not commenting on the post itself, I do not hold a Facebook account. Anyway this is a long write, so it may as well deserve a post of its own. Some of the work Mark is describing already exists under openark kit&#8216;s oak-online-alter-table. Allow me [...]]]></description>
			<content:encoded><![CDATA[<p>In response to Mark Callaghan&#8217;s post <a href="http://www.facebook.com/note.php?note_id=356997370932">mk-schema-change</a>.</p>
<p>I apologize for not commenting on the post itself, I do not hold a Facebook account. Anyway this is a long write, so it may as well deserve a post of its own.</p>
<p>Some of the work Mark is describing already exists under <a href="http://code.openark.org/forge/openark-kit">openark kit</a>&#8216;s <a href="http://code.openark.org/forge/openark-kit/oak-online-alter-table">oak-online-alter-table</a>. Allow me to explain what I have gained there, and how the issue can be further pursued. There is relevance to Mark&#8217;s suggestion.</p>
<p><em>oak-online-alter-table</em> uses a combination of locks, chunks and triggers to achieve an almost non-blocking <strong>ALTER TABLE</strong> effect. I had a very short opportunity to speak with Mark on last year&#8217;s conference, in between bites. Mark stated that anything involving triggers was irrelevant in his case.</p>
<p>The triggers are a pain, but I believe a few other insights from <em>oak-online-alter-table</em> can be of interest.<span id="more-2144"></span></p>
<h4>The first attempt</h4>
<p>My first attempt with the script assumed:</p>
<ul>
<li>Table has an <strong>AUTO_INCREMENT PRIMARY KEY</strong> column</li>
<li>New rows always gain ascending <strong>PRIMARY KEY</strong> values</li>
<li><strong>PRIMARY KEY</strong> never changes for an existing row</li>
<li><strong>PRIMARY KEY</strong> values are never reused</li>
<li>Rows may be deleted at will</li>
<li>No triggers exist on the table</li>
<li>No <strong>FOREIGN KEY</strong>s exist on the table.</li>
</ul>
<p>So the idea was: when one wants to do an <strong>ALTER TABLE</strong>:</p>
<ol>
<li>Create a <em>ghost</em> table with the new structure.</li>
<li>Read the minimum and maximum PK values.</li>
<li>Create <strong>AFTER INSERT</strong>, <strong>AFTER UPDATE</strong>, <strong>AFTER DELETE</strong> triggers on the original table. These triggers will propagate the changes onto the <em>ghost</em> table.</li>
<li>Working out slowly, and in small chunks, copy rows within recorded min-max values range into the <em>ghost</em> table. The interesting part is where the script makes sure there&#8217;s no contradiction between these actions and those of the triggers, (whichever came first!). This is largely solved using <strong>INSERT IGNORE</strong> and <strong>REPLACE INTO</strong> in the proper context.</li>
<li>Working out slowly and in chunks again, we <em>remove</em> rows from the <em>ghost</em> table, which are no longer existent in the original table.</li>
<li>Once all chunking is complete, <strong>RENAME</strong> original table to *_old, and <em>ghost</em> table in place of the original table.</li>
</ol>
<p>Steps <strong>4</strong> &amp; <strong>5</strong> are similar in concept to transactional recovery through <em>redo logs</em> and <em>undo logs</em>.</p>
<h4>The next attempt</h4>
<p>Next phase removed the <strong>AUTO_INCREMENT</strong> requirement, as well as the &#8220;no reuse of PK&#8221;. In fact, the only remaining constraints were:</p>
<ul>
<li>There is some <strong>UNIQUE KEY</strong> on the table which is unaffected by the <strong>ALTER</strong> operation</li>
<li>No triggers exist on the table</li>
<li>No <strong>FOREIGN KEY</strong>s exist on the table.</li>
</ul>
<p>The steps are in general very similar to those listed previously, only now a more elaborate chunking method is used with possible non-integer, possible multi-column chunking algorithm. Also, the triggers take care of changes in <strong>UNIQUE KEY</strong> values themselves.</p>
<h4>mk-schema-change?</h4>
<p>Have a look at the <a href="http://code.google.com/p/openarkkit/w/list">wiki pages</a> for OnlineAlterTable*. There is some discussion on concurrency issues; on transactional behavior, which explains why <em>oak-online-alter-table</em> performs correctly. Some of these are very relvant, I believe, to Mark&#8217;s suggestion. In particular, making the chunks copy; retaining transactional integrity, etc.</p>
<p>To remove any doubt, <em>oak-online-alter-table</em> is<em> </em> <strong>not production ready</strong> or anywhere near. Use at your own risk. I&#8217;ve seen it work, and I&#8217;ve seen it crash. I got little feedback and thus little chance to fix things. I also didn&#8217;t touch the code for quite a few months now, so I&#8217;m a little rusty myself.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/mk-schema-change-check-out-ideas-from-oak-online-alter-table/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>RPM builds for openark kit</title>
		<link>http://code.openark.org/blog/mysql/rpm-builds-for-openark-kit</link>
		<comments>http://code.openark.org/blog/mysql/rpm-builds-for-openark-kit#comments</comments>
		<pubDate>Thu, 10 Dec 2009 07:41:35 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[openark kit]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=1735</guid>
		<description><![CDATA[Thanks to Lenz Grimmer, openark kit is now available in RPM format. .DEB or python packages are available, as usual, on project page on Google Code. Thank you, Lenz!]]></description>
			<content:encoded><![CDATA[<p>Thanks to <a href="http://www.lenzg.net/">Lenz Grimmer</a>, <a href="http://code.openark.org/forge/openark-kit">openark kit</a> is now <a href="http://software.opensuse.org/search?baseproject=ALL&amp;p=1&amp;q=openark-kit">available in RPM</a> format.</p>
<p>.DEB or python packages are available, as usual, on <a href="http://code.google.com/p/openarkkit/">project page on Google Code</a>.</p>
<p>Thank you, Lenz!</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/rpm-builds-for-openark-kit/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>New and Noteworthy in openark kit</title>
		<link>http://code.openark.org/blog/mysql/new-and-noteworthy-in-openark-kit</link>
		<comments>http://code.openark.org/blog/mysql/new-and-noteworthy-in-openark-kit#comments</comments>
		<pubDate>Tue, 30 Jun 2009 06:38:27 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[openark kit]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=853</guid>
		<description><![CDATA[A new release of openark kit is out. Some interesting additions.changes are: oak-online-alter-table: now works with multicolumn UNIQUE KEYs New: oak-chunk-update: break an long running or non indexed UPDATE/DELETE to small chunks oak-purge-master-logs, oak-show-replication-status: support for non standard slave ports openark kit is a set of utilities for MySQL, helping in easing out everyday&#8217;s work. [...]]]></description>
			<content:encoded><![CDATA[<p>A new release of <a href="http://code.openark.org/forge/openark-kit">openark kit</a> is out. Some interesting additions.changes are:</p>
<ul>
<li><a href="http://code.openark.org/forge/openark-kit/oak-online-alter-table">oak-online-alter-table</a>: now works with multicolumn UNIQUE KEYs</li>
<li>New: <a title="oka-chunk-update" href="http://code.openark.org/forge/openark-kit/oak-chunk-update">oak-chunk-update</a>: break an long running or non indexed UPDATE/DELETE to small chunks</li>
<li><a href="http://code.openark.org/forge/openark-kit/oak-purge-master-logs">oak-purge-master-logs</a>, <a href="http://code.openark.org/forge/openark-kit/oak-show-replication-status">oak-show-replication-status</a>: support for non standard slave ports</li>
</ul>
<p>openark kit is a set of utilities for MySQL, helping in easing out everyday&#8217;s work. Let&#8217;s look more closely at the changes.</p>
<h4>oak-online-alter-table</h4>
<p>The utility allows for non-blocking ALTER TABLE operations, under certain limitations. One limitation which has been removed in the current release was the single-column UNIQUE KEY limitation. As of now, a requirement for running <strong>oak-online-alter-table</strong> is that the altered table has <em>some</em> UNIQUE KEY. It could be numerical, textual, single column, multi-column (compound), anything.<span id="more-853"></span></p>
<p>Other requirements:</p>
<ul>
<li>The table must not have any FOREIGN KEY association (neither parent nor child). This will be the next requirement to change. Support for child-side FOREIGN KEY will be added. At current, I do not see a solution for parent-side.</li>
<li>The altered table must share a UNIQUE KEY with the original one (that is, at least one UNIQUE KEY must stay in place after altering the table).</li>
<li>The table must not have any &#8216;AFTER&#8217; triggers defined. At current, I do not see a solution for that, the reason being that the utility needs to create those triggers as port of its mechanism, and that MySQL does not allow for atomic alteration of triggers. Also see <a href="http://code.openark.org/blog/mysql/why-of-the-week">this post</a>.</li>
<li>Some operations, such as TRUNCATE, OPTIMIZE etc. are not permitted on the table while the utility works.</li>
</ul>
<p>There was need (and there still is) for many MySQL issues workarounds. I&#8217;ll update as work progresses.</p>
<h4>oak-chunk-update</h4>
<p>Using similar techniques to oak-online-alter-table, and requiring a UNIQUE KEY on a table, this utility allows for breaking of a long running, or a non-indexed query, into small chunks, thereby allowing for relatively non blocking UPDATE/DELETE operations.</p>
<p>For example, a <strong>DELETE FROM log WHERE log_ts &lt; &#8217;2009-01-01 00:00:00&#8242;</strong> might prove to be a long running query. If the log_ts column is not indexed, the table is virtually locked, whether this was MyISAM or InnoDB. Assuming an AUTO_INCREMENT column called &#8216;id&#8217; exists (any UNIQUE KEY will do, so this is just an example), we can provide the following query as argument to oak-chunk-update:</p>
<blockquote>
<pre>DELETE FROM log WHERE log_ts &lt; '2009-01-01 00:00:00' AND <strong>OAK_CHUNK(log.id)</strong></pre>
</blockquote>
<p>The utility will parse the magic token <strong>OAK_CHUNK(&#8230;)</strong>, and will work the query over distinct ranges, e.g.:</p>
<blockquote>
<pre>DELETE FROM log WHERE log_ts &lt; '2009-01-01 00:00:00' AND log.id &gt; 11000 AND log.id &lt;= 12000
DELETE FROM log WHERE log_ts &lt; '2009-01-01 00:00:00' AND log.id &gt; 12000 AND log.id &lt;= 13000
etc.</pre>
</blockquote>
<p>While the above can also be easily solved using a simple stored procedure, the magic becomes more interesting when you have a compound UNIQUE KEY, which may have non integral columns.</p>
<p>The utility also supports operations on multiple tables. Thus, one can use <strong>DELETE FROM t1 USING t1,t2&#8230;</strong>, for example, as long as an <strong>OAK_CHUNK(&#8230;)</strong> is proivded on one of the tables. It is interesting to see how the choice of table affects the chunking process.</p>
<h4>oak-purge-master-logs, oak-show-replication-status</h4>
<p>The two now support non default ports for slaves. This is achieved by utilizing the <strong>report_port</strong> parameter on the slaves, reading the value on <strong>SHOW SLAVE HOSTS</strong> (see <a href="http://code.openark.org/blog/mysql/the-importance-of-report_host-report_port">this post</a>). Both utilities support skipping <strong>SHOW SLAVE HOSTS</strong> and just picking up slaves by looking at <strong>SHOW PROCESSLIST</strong>.</p>
<h4>Bugs</h4>
<p>I&#8217;ve had issues with Google&#8217;s Issues, which made me leave a couple of unanswered issues for a couple of months. Brrrr. (BTW both were only related to prerequisites). I&#8217;ll resolve my issues issues. I&#8217;m looking forward for input, even though my spare time is little these days.</p>
<h4>Acknowledgments</h4>
<p>Writing of the toolkit is mostly done at my spare time, though being utilized in my professional work. Recently, a customer in urgent need has agreed for paying out for required development time on these scripts, while recognizing the open source model and license under which it is being developed and released, and removing all claims for copyright. I very much appreciate the customer&#8217;s approach and wish to acknowledge his contribution.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/new-and-noteworthy-in-openark-kit/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Online ALTER TABLE now available in openark kit</title>
		<link>http://code.openark.org/blog/mysql/online-alter-table-now-available-in-openark-kit</link>
		<comments>http://code.openark.org/blog/mysql/online-alter-table-now-available-in-openark-kit#comments</comments>
		<pubDate>Tue, 24 Mar 2009 16:19:59 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[openark kit]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=629</guid>
		<description><![CDATA[A new utility in openark kit allows for online ALTER TABLE operation. That is, the modification of table structure without locking down the entire table for the duration of the operation. The oak-online-alter-table utility works under the following restrictions: The table has at least one single-column UNIQUE KEY [*] Altered table shares a single-column UNIQUE [...]]]></description>
			<content:encoded><![CDATA[<p>A new utility in <a title="openark kit home page" href="http://code.openark.org/forge/openark-kit">openark kit</a> allows for online ALTER TABLE operation. That is, the modification of table structure without locking down the entire table for the duration of the operation. The <a title="oak-online-alter-table utility" href="http://code.openark.org/forge/openark-kit/oak-online-alter-table">oak-online-alter-table</a> utility works under the following restrictions:</p>
<ul>
<li>The table has at least one single-column UNIQUE KEY <em>[*]</em></li>
<li>Altered table shares a single-column UNIQUE KEY with the original table <em>[*]</em></li>
<li>No &#8216;AFTER&#8217; triggers are defined on the table (the utility creates its own triggers for the duration of the operation)</li>
<li>The table has no FOREIGN KEYs <em>[*][#]</em></li>
<li>Table name is no longer than 57 characters</li>
</ul>
<p><em>[*]: Restriction is scheduled to be removed or partly removed.</em></p>
<p><em>[#]: &#8216;Child-side&#8217; foreign keys may actually work, but have not been tested.<br />
</em></p>
<p>Follows is a mini FAQ which attempts to introduce the utility.</p>
<h4>So what exactly does this utility provide?</h4>
<ul>
<li>First and foremost, the ability to perform a non blocking ALTER TABLE. This has long been an issue with MySQL, and complex Master-Master, application aware solutions are currently required in order to perform an ALTER TABLE with minimal downtime. The utility offers a no-downtime solution, albeit there is performance penalty for the duration of its runtime, and some requirements to meet.</li>
<li>It also supports a &#8216;null&#8217; ALTER. That is, an ALTER TABLE which does not change anything. This effectively means rebuilding of the table. For InnoDB tables with innodb_file_per_table, for example, this could be the means of regaining disk space after removing many rows from the table. Also, while it does not strictly act like OPTIMIZE TABLE, the effect of running this utility should build a better organized table on disk (this as yet unverified).</li>
<li>Another thing this utility supports is the building of a ghost table: a duplicate of a given table, which keeps mirroring the original table via triggers. <em>[May be removed in future versions]</em></li>
</ul>
<h4><span id="more-629"></span>How does it work?</h4>
<p>Well, there are some wiki pages <a href="http://code.google.com/p/openarkkit/wiki/OakOnlineAlterTableSteps">[1]</a> <a href="http://code.google.com/p/openarkkit/wiki/OakOnlineAlterTableConcurrency">[2]</a> <a href="http://code.google.com/p/openarkkit/wiki/OakOnlineAlterTableConstraints">[3]</a> which explain the details, but in general it goes as follows:</p>
<ol>
<li>The utility creates an empty &#8216;ghost&#8217;  table, a copy of the original</li>
<li>The ghost table is ALTERed (or left unchanged, if no ALTER specified)</li>
<li>Triggers are created on the original table, which propagate changes to the ghost table.</li>
<li>In two passes, data is copied from the original table to the ghost table, then reviewed for deletion.</li>
<li>The ghost table is renamed to take place of the original table; the original table is dropped.</li>
</ol>
<p>Here&#8217;s an invocation sample, in which we modify the type of the AUTO_INCREMENT column, add a column, add a key and drop a column &#8211; all at the same time, all online:</p>
<blockquote>
<pre>oak-online-alter-table -u root --ask-pass --socket=/tmp/mysql.sock --database=world --table=City --alter="MODIFY Id BIGINT UNSIGNED AUTO_INCREMENT, ADD COLUMN Mayor VARCHAR(64) CHARSET utf8, DROP COLUMN District, ADD KEY(Population)"</pre>
</blockquote>
<h4>What kind of ALTERs are supported?</h4>
<ul>
<li>ADD COLUMN (new column must have a default value)</li>
<li>DROP COLUMN (as long as there&#8217;s still a shared single-column UNIQUE KEY between the old table and the altered one)</li>
<li>MODIFY COLUMN (change type, including UNIQUE KEY columns)</li>
<li>ADD KEY (normal, unique, fulltext etc.)</li>
<li>DROP KEY (as long as there&#8217;s still a shared single-column UNIQUE KEY between the old table and the altered one)</li>
<li>Change ENGINE: works, but great care should be taken when dealing with non-transactional engines</li>
<li>Adding FOREIGN KEY constraints is possible</li>
<li>More&#8230; Not all ALTERS have been tested, e.g. CONVERT, partition handling&#8230;</li>
<li>none: it is possible to just do an online rebuild of the table, with no modification to its structure</li>
</ul>
<p>The following are not allowed <em>while the utility is running</em>:</p>
<ul>
<li>An ALTER TABLE on the original table (well, obviously)</li>
<li>A TRUNCATE on the original table</li>
<li>LOAD DATA INFILE into the original table</li>
<li>OPTIMIZE on the original table</li>
</ul>
<p>In short, while this utility runs, just act normal&#8230;</p>
<h4>Which engines are supported?</h4>
<p>MyISAM &amp; InnoDB are both supported. Any engine which uses table level locks is implicitly supported (Memory, Archive). There is currently no support for Maria (transactional), PBXT or Falcon. No plans for the near future include these.</p>
<p>It is possible to ALTER the ENGINE of a table, but this is highly unrecommended (due to differences in transactional behavior, or lack of transactional support altogether).</p>
<p>With InnoDB, and when running long transactions during the runtime of this utility, one of the steps (which requires a LOCK TABLES&#8230;WRITE) may take some time to complete: it repeatedly attempts to set up locks until successful. However, there is no blocking during these attempts, and the lock time, once the locks are gained, is minor.</p>
<h4>What impact does this utility have?</h4>
<p>For the duration of runtime, you can expect a performance penalty. There are many reasons for that:</p>
<ul>
<li>Triggers are added to your table. This, by itself, is performance penalty.</li>
<li>Any changes to your table is propagated to the ghost table. So every INSERT makes for two, actually.</li>
<li>More locks are held. While this utility is non-blocking, it does lock small chunks in turns, and for very short periods. But still locks are held.</li>
<li>While the ghost table is being built, disk space of up to the same size as your original table is consumed. Depending on your ENGINE and storage means, some disk space may be released later on.</li>
</ul>
<h4>I was drunk when I decided to run it, but now that I&#8217;m sober, I find out it&#8217;s still running and I want to undo everything!</h4>
<p>OK. First, don&#8217;t drink and DBA. Next, stop the utility, run it again with &#8211;cleanup. All should be back to normal.</p>
<h4>How mature is this utility? I think there&#8217;s a bug!</h4>
<p>It is <em>very</em> experimental. It seems to be working well as far as I know, but community feedback is appreciated. Please report bugs <a href="http://code.google.com/p/openarkkit/issues/list">here</a>. Thank you!</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/online-alter-table-now-available-in-openark-kit/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Blocking user accounts</title>
		<link>http://code.openark.org/blog/mysql/blocking-user-accounts</link>
		<comments>http://code.openark.org/blog/mysql/blocking-user-accounts#comments</comments>
		<pubDate>Thu, 05 Mar 2009 09:44:40 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=443</guid>
		<description><![CDATA[A long time missing feature in MySQL is temporarily blocking accounts: denying a user to log in, without affecting any other of her privileges. There is no such privilege as &#8216;LOGIN&#8217; in the grants table, as the ability to log in is the most basic one MySQL allows. This basic privilege is called USAGE. I&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p>A long time missing feature in MySQL is temporarily blocking accounts: denying a user to log in, without affecting any other of her privileges.</p>
<p>There is no such privilege as &#8216;LOGIN&#8217; in the grants table, as the ability to log in is the most basic one MySQL allows. This basic privilege is called USAGE.</p>
<p>I&#8217;ll present a hack around this, one which <a title="openark kit: oak-block-account" href="http://code.openark.org/forge/openark-kit/oak-block-account">oak-block-account</a> implements. Before presenting the hack, lets lay down some requirements:</p>
<ul>
<li>A user can be blocked from logging in to MySQL.</li>
<li>Such a blocked user can later be &#8216;released&#8217;, re-enabling him to log in.</li>
<li>It should be possible to determine if a certain user is currently blocked or not.</li>
</ul>
<p><span id="more-443"></span>A first attempt to answer the above requirements is to change the account&#8217;s password. As a naive example, we can set an account&#8217;s password to &#8216;aaaaaaaaa&#8217;. But let&#8217;s consider the following:</p>
<ul>
<li>Will the user be unable to find, by some algorithm or by brute force, the new password?</li>
<li>How can we revert the new password to the original one?</li>
</ul>
<p>Time to look at how MySQL stores passwords, then.</p>
<p>We begin by distinguishing old_passwords (variable <strong>old_passwords</strong>=1) from new passwords.</p>
<ul>
<li>Old passwords are 16 characters long. These are hexadecimal characters.</li>
<li>New passwords are 41 characters long: a leading &#8216;*&#8217; followed by 40 hexadecimal characters.</li>
</ul>
<h4>Blocking with &#8216;new passwords&#8217;</h4>
<p>To disable an account using a &#8216;new password&#8217;, the trick is simply to reverse the password in the <strong>mysql.user</strong> table. So if my password was &#8217;123456&#8242; (strong one, isn&#8217;t it?), then <strong>mysql.user</strong> will have:</p>
<blockquote>
<pre>mysql&gt; select PASSWORD('123456');
+-------------------------------------------+
| PASSWORD('123456')                        |
+-------------------------------------------+
| *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+-------------------------------------------+</pre>
</blockquote>
<p>To encode, we do:</p>
<blockquote>
<pre>SET PASSWORD FOR 'some_user'@'some_host' = '9DA2AC2DE76CD7ADD8654EE50192347BE7384BB6*'</pre>
</blockquote>
<p>Let&#8217;s consider the implication of what we just did:</p>
<ul>
<li>The new password is valid, as far as MySQL is concerned. No questions asked.</li>
<li>The user cannot log in with his old password.</li>
<li>Nor can the user log in with <em>any other</em> password, since the <strong>PASSWORD()</strong> function will never return a password ending with &#8216;*&#8217;.</li>
<li>It is easy to see that the user is &#8216;blocked&#8217;: his password ends with &#8216;*&#8217;.</li>
<li>It is easy to restore the original password: we simply reverse the text and call <strong>SET PASSWORD</strong> again.</li>
</ul>
<h4>Blocking with &#8216;old passwords&#8217;</h4>
<p>This part really assumes you&#8217;re using MySQL 4.1 or above. If you&#8217;re one of those &#8216;few&#8217; lucky people, but are unfortunately using old_passwords, here&#8217;s the deal:</p>
<p>Reversing an old password won&#8217;t do, since:</p>
<ul>
<li>The reverse may still consist of an encoding for some password</li>
<li>It&#8217;s impossible to tell if a user is blocked or not.</li>
</ul>
<p>MySQL will only allow 16 or 41 character long passwords (anyway that&#8217;s my finding). So to encode a 16 characters long password, we pad it with 25 (= 41-16) &#8216;~&#8217; characters. Thus, the encoded password &#8216;abcdef0123456789&#8242; turns to &#8216;~~~~~~~~~~~~~~~~~~~~~~~~~abcdef0123456789&#8242;. Again, note the following:</p>
<ul>
<li>The new password is accepted by MySQL as valid.</li>
<li>The user cannot log in with his old password.</li>
<li>Nor can the user log in with <em>any other</em> password, since the <strong>PASSWORD()</strong> function will never return a password starting with &#8216;~&#8217;.</li>
<li>It is easy to see that the user is &#8216;blocked&#8217;: his password starts with 25 &#8216;~&#8217; characters.</li>
<li>It is easy to restore the original password: we simply remove the leading &#8216;~&#8217; characters and call <strong>SET PASSWORD</strong> again.</li>
</ul>
<h4>oak-block-account</h4>
<p>No need to work all this by hand. <a title="openark kit: oak-block-account" href="http://code.openark.org/forge/openark-kit/oak-block-account">oak-block-account</a> is a utility which does exactly that. It can block, release, and even kill accounts. It will automatically detect if the password is &#8216;old&#8217; or &#8216;new&#8217;, or if the account is already blocked or not.</p>
<h4>Other possibilities</h4>
<p>RENAME USER is another trick which could be used: we could take a user&#8217;s login (e.g. &#8216;webuser&#8217;) and rename it to an unknown value, like &#8216;webuser__1q98d4f&#8217;. While it serves the same purpose &#8211; of blocking the user, it has a disadvantage: if by luck or hack the new login is discovered, it could still be used to access the database. The change of password solution ensures there is no user/password combination which will work on the blocked account.</p>
<p>Other options may involve removing the account from <strong>mysql.user</strong>, to put it elsewhere, from where to restore the row when the time comes. I prefer a solution which works on the <strong>mysql</strong> schema itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/blocking-user-accounts/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Announcing openark kit</title>
		<link>http://code.openark.org/blog/mysql/announcing-openark-kit</link>
		<comments>http://code.openark.org/blog/mysql/announcing-openark-kit#comments</comments>
		<pubDate>Wed, 25 Feb 2009 11:55:45 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=596</guid>
		<description><![CDATA[It is my great pleasure to announce the availability of the openark kit, a set of lightweight utilities for MySQL, which eases every day tasks. The available tools are: oak-apply-ri: apply referential integrity on two columns with parent-child relationship. oak-block-account: block or release MySQL users accounts, disabling them or enabling them to login. oak-kill-slow-queries: terminate [...]]]></description>
			<content:encoded><![CDATA[<p>It is my great pleasure to announce the availability of the <a title="openark kit project home page" href="http://code.openark.org/forge/openark-kit">openark kit</a>, a set of lightweight utilities for MySQL, which eases every day tasks.</p>
<p>The available tools are:</p>
<ul>
<li><a title="oak-apply-ri" href="http://code.openark.org/forge/openark-kit/oak-apply-ri">oak-apply-ri</a>: apply referential integrity on two columns with parent-child  relationship.</li>
<li><a title="oak-block-account" href="http://code.openark.org/forge/openark-kit/oak-block-account">oak-block-account</a>: block or release MySQL users accounts, disabling them or enabling them to login.</li>
<li><a title="oak-kill-slow-queries" href="http://code.openark.org/forge/openark-kit/oak-kill-slow-queries">oak-kill-slow-queries</a>: terminate long running queries.</li>
<li><a title="oak-modify-charset" href="http://code.openark.org/forge/openark-kit/oak-modify-charset">oak-modify-charset</a>: change the character set (and collation) of a textual column.</li>
<li><a title="oak-purge-master-logs" href="http://code.openark.org/forge/openark-kit/oak-purge-master-logs">oak-purge-master-logs</a>: purge master logs, depending on the state of replicating slaves.</li>
<li><a title="oak-security-audit" href="http://code.openark.org/forge/openark-kit/oak-security-audit">oak-security-audit</a>: audit accounts, passwords, privileges and other security settings.</li>
<li><a title="oak-show-limits" href="http://code.openark.org/forge/openark-kit/oak-show-limits">oak-show-limits</a>: show AUTO_INCREMENT “free space”.</li>
<li><a title="oak-show-replication-status" href="http://code.openark.org/forge/openark-kit/oak-show-replication-status">oak-show-replication-status</a>: show how far behind are replicating slaves on a given master.</li>
</ul>
<p><span id="more-596"></span>All tools are written in Python, and require Python 2.3 or newer, and the python-mysqldb driver.</p>
<p>The project is hosted in <a title="openark kit Google Code page" href="http://code.google.com/p/openarkkit/">Google Code</a>, where you can find downloads, issue tracking etc. Community feedback is requested and welcome. Please use the &#8216;Issues&#8217; mechanism to report bugs.</p>
<p>The openark kit is released under the <a href="http://www.opensource.org/licenses/bsd-license.php">BSD license</a>.</p>
<p>All utilities have been put to work on production, yet all are still being developed, and still more are being created, as new ideas and needs emerge. I have been using custom made scripts for handling DB issues for years, and finally have decided to formalize them and to support them as an open source project. I do hope you try them out.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/announcing-openark-kit/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
