<?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</title>
	<atom:link href="http://code.openark.org/blog/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</generator>
		<item>
		<title>MySQL command line vs. visual editors - reflections</title>
		<link>http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors-reflections</link>
		<comments>http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors-reflections#comments</comments>
		<pubDate>Wed, 01 Feb 2012 08:19:12 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Opinions]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4647</guid>
		<description><![CDATA[My previous post drew some attention, and in particular two comments I wish to relate to. I also wish to make a more fine-grained observation on visual editors. One comment is by Peter Laursen, who rejected the generalization in my post, and another by wlad, who was harsher (but to the point), suggesting my post [...]]]></description>
			<content:encoded><![CDATA[<p>My <a href="http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors">previous post</a> drew some attention, and in particular two comments I wish to relate to. I also wish to make a more fine-grained observation on visual editors.</p>
<p>One comment is by <em><a href="http://www.webyog.com/">Peter Laursen</a></em>, who rejected the generalization in my post, and another by <em>wlad</em>, who was harsher (but to the point), suggesting my post translated to <em>"I don't know it, therefore it sucks"</em>.</p>
<p>I must have delivered the wrong message, since apparently people read my post as "don't use visual editors, they are bad for you", which is not what I intended to say, nor is it what I actually <em>think</em>. I took a very specific aspect of visual editors and commented on that. My comment should not extrapolate to "anything about visual editors is bad".</p>
<p>I don't think people should only be using the command line, and am not in the least interested in vi/emacs/eclipse/netbeans kind of wars. Of course everyone should be using whatever works best for them in terms of productivity and ease of use. And of course visual editors have great advantages over command line.</p>
<p><span id="more-4647"></span>I'm sorry, it would be childish to assume otherwise, and extra-extra-extrapolation to suggest that was my hidden meaning.</p>
<h4>Reflections on Peter's comments</h4>
<p>I can see that my post was harsh on visual editors, and agree one cannot just generalize on the dozens of editors available. I have used a few tools, and only to some extent, since I personally feel more comfortable with command line, and so I cannot possibly generalize on all tools. Nor are they all equal.</p>
<p>My point is, there is one de-facto tool, which is the command-line, for which there are no hidden assumptions. For which I don't need to investigate whether a new connection is being opened, or if my query is somehow modified, or... I guess one can say "hey, my tool does nothing of the sort and acts just like the command line". I'm not arguing. The visual editor is an additional layer between you and the server (the <em>mysql</em> command line client is in itself a layer, but a very transparent one, a very low level one), one which needs to take care of visual issues, such as display space, GUI components, widgets not running out of memory, responsiveness, good looks. These, one way or the other, add complexity to the discussion between yourself and your database.</p>
<p>One can say "it's all configurable, there's good documentation, you should know the tool you are using". To some extent the same can be said of the command line client. Here is an observation of mine, please consider it as user input: many (I don't know if <em>most</em>) users will not bother modifying the settings. Many will feel uncomfortable with turning checkboxes on and off, or modify thresholds. It is similar in essence to users not modifying the default InnoDB settings for the MySQL server, working with <strong>8MB</strong> of buffer pool.</p>
<p>Anyway I agree my post was over-generalizing on the criticism of visual editors. Sorry for that. It should have been more specific on the advantages of command line.</p>
<h4>Reflections on wlad's comments</h4>
<p>Since I wanted to concentrate on the command line issue, I didn't elaborate on other stuff. For example, I didn't specify on what type of trainings I ask students to close down their visual editors and open up a command line. Perhaps one could read as <em>"from this moment on, and for the entire duration of the training, no one should be using visual editors, and anyone who does will find himself/herself out of the class"</em>. I really didn't think to elaborate on that, and even now - wow, it will take me ages to tell the full story. So I will be extra-brief:</p>
<p>I do make that suggestion. I do that when I start discussion of keys &amp; execution plans. I don't enforce that. I don't mind which tool a developer uses. I actually tell them about various GUI tools they can use (naming the ones I see as most popular among other students).</p>
<p>But I also do <em>not</em> turn my training to <em>"I'm going to do this session using the same tools you are using just because you are using them and you are in this class"</em>.</p>
<p>There is a multi-layered reasoning for that:</p>
<ul>
<li>Many times there is a mixture of tools in the classroom. I can't just pick up on one. The command line is the most common tool everyone can agree upon. I sometimes demonstrate on MySQL Workbench since many are familiar with it being an "official" GUI tool by the same company which makes the database.</li>
<li>If I dwell on the particulars of a GUI tool, this consumes precious time that must be used to explain the EXPLAIN and talk about INDEX in depth. I just don't have that time on training. The command line consumes very little time for me.</li>
<li>I also don't see that I should demonstrate using commercial products. I have nothing against commercial, and on occasion I buy commercial, and I certainly do not slight a commercial product just because it's commercial, but I prefer to sponsor open source. If students have a commercial product, I don't see this is my duty to walk them through the product.</li>
<li>There are actually a few more reasons; operating systems, installations, assumptions on installed software, strict system administrators who would not installed anything I would tell them, projectors, font sizes, contrast of colors on projected image, ... Believe me, I've been doing this for years, there are <em>many</em> factors to <em>any</em> small decision in class.</li>
</ul>
<p>Last, I wish to relate to wlad's <em>"I don't know it. It sucks"</em> attribution to my post.</p>
<p>It is true there is not one single SQL GUI tool I know bottoms up. And the status is deteriorating, since I've long since decided my personal preference is command line. This makes me a non-expert, no-authority on any GUI tool. I actually present myself as such in class. This does not lower the quality of the training; it's an aspect outside the training (for the reasons I mentioned above). I therefore agree to <em>"I don't know it"</em>.</p>
<p>Now, I strongly believe I do not make the connection to <em>"therefore it sucks"</em>. I think that's an exaggerated extrapolation of what I said. But it is such an overwhelming statement about myself for me to read, that I will keep it in mind. It's a good thing to keep in mind, not only on GUI tools, but also in real life.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors-reflections/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MySQL command line vs. visual editors</title>
		<link>http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors</link>
		<comments>http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors#comments</comments>
		<pubDate>Mon, 30 Jan 2012 15:04:34 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[Opinions]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4639</guid>
		<description><![CDATA[Students in my training classes usually prefer to use some kind of visual editor for MySQL. Typically this would be the software they're using at work. Sometimes they just bring over their laptops with the software installed. Or they would use MySQL Workbench, which is what I usually have pre-installed on their desktops. I see [...]]]></description>
			<content:encoded><![CDATA[<p>Students in my training classes usually prefer to use some kind of visual editor for MySQL. Typically this would be the software they're using at work. Sometimes they just bring over their laptops with the software installed. Or they would use MySQL Workbench, which is what I usually have pre-installed on their desktops.</p>
<p>I see MySQL Workbench, SQLyog, Toad for MySQL, or several more.</p>
<p>I always humbly suggest they <em>close down their software and open up a command line</em>.</p>
<p>It isn't fancy. It may not even be convenient (especially on Windows, in my opinion). And repeating your last command with a minor modification requires a lot of key stroking. Or you would copy+paste from some text editor. Most students will give it a shot, then go back to their favorite editor.</p>
<p>Well, again and again I reach the same conclusion:</p>
<h4>Visual editors are not as trustworthy as the command line.</h4>
<p>Time and again students show me something on their editor. Behavior seems strange to me. Opening up a console shows a completely different picture.</p>
<p>Things like:<span id="more-4639"></span></p>
<ul>
<li>The visual editor would open a new connection for every new query (oh, so the <strong>@user_defined_variable</strong> I've just assigned turns <strong>NULL</strong>, or the <strong>TEMPORARY TABLE</strong> disappears).</li>
<li>The visual editor will only show <strong>1,000</strong> results, via <strong>LIMIT 0,1000</strong>. "But the same query runs <em>so much faster</em> on my machine!". Well, sure, a <strong>filesort</strong> of <strong>1,000,000</strong> rows that can satisfy the first <strong>1,000</strong> will quit early!</li>
<li>The visual editor shows table definition graphically. "I didn't realize the index did(n't) cover this and that columns. I didn't realize it only covered first <strong>n</strong> characters of my <strong>VARCHAR</strong>.". That's because you can't beat <strong>SHOW CREATE TABLE</strong>, the definite table structure description.</li>
<li>The visual editor allows for export/import/copy/transfer of tables and rows with just one click! "Why is it so complicated in the command line to purge <strong>1,000,000</strong> rows from a table?". Ummm, did you realize the visual editor would typically use a naive approach of doing everything in one huge transaction?</li>
<li>The visual editor is smart. But sometimes you don't want smart. You just <a href="http://www.devart.com/blogs/dbforge/index.php/mind-data-modifications-via-data-editor-in-dbforge-studio-for-mysql.html">assume simple</a>. I personally take great precaution with <em>smart</em> solutions. Luckily, with scripts you have so much greater control (i.e. command line options, "dry-run" mode, etc.) that I have greater confidence in them.</li>
</ul>
<p>I do like it when a visual editor plays it both <em>smart</em> and <em>safe</em>, in such way that before doing its smart work it actually presents you with <em>the query it's going to issue</em>. Which is why I always considered MySQL Query Browser (now replaced by Workbench) to be the visual editor of choice in my classes.</p>
<p>But, at the end of the day, I strongly believe: if you don't know how to do it with command line, you can't really know how it's done.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/mysql-command-line-vs-visual-editors/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Syntax of the day: IS TRUE and IS FALSE</title>
		<link>http://code.openark.org/blog/mysql/syntax-of-the-day-is-true-and-is-false</link>
		<comments>http://code.openark.org/blog/mysql/syntax-of-the-day-is-true-and-is-false#comments</comments>
		<pubDate>Thu, 26 Jan 2012 04:09:23 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Syntax]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4198</guid>
		<description><![CDATA[What makes for a true statement? We usually test statements using a WHERE clause: SELECT * FROM world.City WHERE Population &#62; 1000000 The "Population &#62; 1000000" statement makes for a boolean expression. Using WHERE is just one way of evaluating it. One can also test with IF(): SET @val := 7; SELECT IF(@val &#62; 2, [...]]]></description>
			<content:encoded><![CDATA[<p>What makes for a <em>true</em> statement?</p>
<p>We usually test statements using a WHERE clause:</p>
<blockquote>
<pre>SELECT * FROM world.City WHERE Population &gt; 1000000</pre>
</blockquote>
<p>The <strong>"Population &gt; 1000000"</strong> statement makes for a boolean expression. Using <strong>WHERE</strong> is just one way of evaluating it. One can also test with <a href="http://dev.mysql.com/doc/refman/5.1/en/control-flow-functions.html#function_if"><strong>IF()</strong></a>:</p>
<blockquote>
<pre>SET @val := 7;
SELECT IF(@val &gt; 2, 'Yes', 'No')</pre>
</blockquote>
<h4>TRUE and FALSE</h4>
<p>The two are keywords. They also map for the numerals <strong>1</strong> and <strong>0</strong>, as follows:</p>
<blockquote>
<pre>mysql&gt; SELECT TRUE, FALSE;
+------+-------+
| TRUE | FALSE |
+------+-------+
|    1 |     0 |
+------+-------+</pre>
</blockquote>
<p>Like in the <strong>C</strong> programming language, a nonzero value evaluates to a <em>true</em> value. A zero evaluates to <em>false</em>. A NULL evaluates to... well, NULL. But aside from 3-valued logic, what's important in our case is that it is <em>not true</em>.<span id="more-4198"></span></p>
<p>However, simple value comparison is incorrect:</p>
<blockquote>
<pre>mysql&gt; SELECT @val, @val &gt; 3, @val &gt; 3 = TRUE as result;
+------+----------+--------+
| @val | @val &gt; 3 | result |
+------+----------+--------+
|    7 |        1 |      1 |
+------+----------+--------+

mysql&gt; SELECT @val, @val = TRUE as result;
+------+--------+
| @val | result |
+------+--------+
|    7 |      0 |
+------+--------+</pre>
</blockquote>
<p>To test for the truth value of an expression, the correct syntax is by using <strong>IS TRUE</strong>:</p>
<blockquote>
<pre>SELECT @val, @val IS TRUE as result;
+------+--------+
| @val | result |
+------+--------+
|    7 |      1 |
+------+--------+</pre>
</blockquote>
<p>Likewise, one may use <strong>IS FALSE</strong> to test for falsehood. However, if you wish to note <strong>NULL</strong> as a <em>false</em> value this does not work:</p>
<blockquote>
<pre>SELECT @empty, @empty IS TRUE, @empty IS FALSE;
+--------+----------------+-----------------+
| @empty | @empty IS TRUE | @empty IS FALSE |
+--------+----------------+-----------------+
| NULL   |              0 |               0 |
+--------+----------------+-----------------+</pre>
</blockquote>
<p>If you're unsure why, you should read more on three-valued logic in SQL. To solve the above, simply use <strong>IS NOT TRUE</strong>:</p>
<blockquote>
<pre>SELECT @empty, @empty IS NOT TRUE;
+--------+--------------------+
| @empty | @empty IS NOT TRUE |
+--------+--------------------+
| NULL   |                  1 |
+--------+--------------------+</pre>
</blockquote>
<p>In summary, use <strong>IS TRUE</strong> and <strong>IS NOT TRUE</strong> so as to normalize truth values into a <strong>0</strong>, <strong>1</strong> value range, <strong>C</strong> style, including handling of <strong>NULL</strong>s.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/syntax-of-the-day-is-true-and-is-false/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Documentation in SQL: CALL for help()</title>
		<link>http://code.openark.org/blog/mysql/documentation-in-sql-call-for-help</link>
		<comments>http://code.openark.org/blog/mysql/documentation-in-sql-call-for-help#comments</comments>
		<pubDate>Wed, 11 Jan 2012 07:01:54 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[common_schema]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[mycheckpoint]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[openark kit]]></category>
		<category><![CDATA[Stored routines]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4536</guid>
		<description><![CDATA[Documentation is an important part of any project. On the projects I maintain I put a lot of effort on documentation, and, frankly, the majority of time spent on my projects is on documentation. The matter of keeping the documentation faithful is a topic of interest. I'd like to outline a few documentation bundling possibilities, [...]]]></description>
			<content:encoded><![CDATA[<p>Documentation is an important part of any project. On the projects I maintain I put a lot of effort on documentation, and, frankly, the majority of time spent on my projects is on documentation.</p>
<p>The matter of keeping the documentation faithful is a topic of interest. I'd like to outline a few documentation bundling possibilities, and the present the coming new documentation method for <a href="http://code.google.com/p/common-schema/" rel="nofollow">common_schema</a>. I'll talk about any bundling that is NOT <em>man pages</em>.</p>
<h4>High level: web docs</h4>
<p>This is the initial method of documentation I used for <a title="openark kit" href="../../forge/openark-kit">openark kit</a> and <a title="mycheckpoint" href="../../forge/mycheckpoint">mycheckpoint</a>. It's still valid for <em>mycheckpoint</em>. Documentation is web-based. You need Internet access to read it. It's in HTML format.</p>
<p>Well, not exactly HTML format: I wrote it in WordPress. Yes, it's HTML, but there's a lot of noise around (theme, menus, etc.) which is not strictly part of the documentation.</p>
<p>While this is perhaps the easiest way to go, here's a few drawbacks:<span id="more-4536"></span></p>
<ul>
<li>You're bound to some framework (WordPress in this case)</li>
<li>Docs are split between MySQL database (my underlying WordPRess storage) &amp; WordPress files (themes, style, header, footer etc.)</li>
<li>Documentation is separate from your code - they're just not in the same place</li>
<li>There is no version control over the documentation.</li>
</ul>
<p>The result is a single source of documentation, which applies to whatever version is latest. It's impossible to maintain docs for multiple versions. You must manually synchronize your WordPress updates with code commits (or rather - code release!).</p>
<h4>Mid level: version controlled HTML docs</h4>
<p>I first saw this approach on Baron's <a href="http://www.xaprb.com/blog/2010/09/22/aspersa-gets-a-user-manual/" rel="bookmark">Aspersa gets a user manual</a> post. I loved it: the documentation is HTML, but stored as part of your project's code, in same version control.</p>
<p>This means one can <a href="http://openarkkit.googlecode.com/svn/trunk/openarkkit/doc/html/introduction.html">browse the documentation</a> (<em>openark kit</em> in this example) exactly as it appears in the baseline. Depending on your project hosting, one may be able to do so per version.</p>
<p>The approach has the great benefit of having the docs tightly coupled with the code in terms of development. Before committing code, one updates documentation for that code, then commits/releases both together.</p>
<p>You're also not bound to any development framework. You may edit with <em>vim, emacs, gedit, bluefish, eclipse,</em> ... any tool of your choice. It's all down to plain old text files.</p>
<h4>Mid level #2: documentation bundling</h4>
<p>One thing I started doing with common_schema is to release a doc bundle with the code. So one can download a compressed bundle of all HTML files. That way one is absolutely certain what's the right documentation for revision <strong>178</strong>. There's no effort about it: the docs are already tightly coupled with code versions. Just compress and distribute.</p>
<h4>Low level: documentation coupled with your code</h4>
<p>Perl scripts can be written as Perl modules, in which case they are eligible for using the <em>perldoc</em> convention. You code your documentation within your script itself, as comment. <em>Perldoc</em> can extract the documentation and present in man-like format. Same happens with Python's <em>pydoc</em>. Baron's <a href="http://www.xaprb.com/blog/2011/11/07/when-documentation-is-code/" rel="bookmark">When documentation is code</a> illustrates that approach. <a href="http://www.maatkit.org/">Maatkit</a> (now <em>Percona Toolkit</em>) has been using it for years.</p>
<p>This method has the advantage of having the documentation ready right within your shell. You don't need a browser, nor firewall access. The docs are just there for you in the same environment where you're executing the code.</p>
<h4>SQL Low level: CALL for help()</h4>
<p><em>common_schema</em> is a different type of project. It is merely a schema. There's no Perl nor Python. One imports the schema into one's MySQL server.</p>
<p>What's the low-level approach for this type of code?</p>
<p>For <em>common_schema</em> I use three levels of documentation: the mid-level, where one can <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/introduction.html">browse through the versioned docs</a>, the 2nd mid-level, where one can <a href="http://code.google.com/p/common-schema/downloads/list">download bundled documentation</a>, and then a low-level approach: documentation embedded within the code.</p>
<p>MySQL's documentation is also built into the server: see the <strong>help_*</strong> tables within the <strong>mysql</strong> schema. The <em>mysql</em> command line client allows one to access help by supporting the help command, e.g.</p>
<blockquote>
<pre>mysql&gt; help create table;</pre>
</blockquote>
<p>The client intercepts this command (this is not server side command) and searches through the <strong>mysql.help_*</strong> docs.</p>
<p>With <em>common_schema</em>, I don't have control over the client; it's all on server side. But the code being a schema, what with stored routines and tables, it's easy enough to set up documentation.</p>
<p>As of the next version of <em>common_schema</em>, and following MySQL's method, <em>common_schema</em> provides a <strong>help</strong> table:</p>
<blockquote>
<pre>DESC help;
+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| topic        | varchar(32) | NO   | PRI | NULL    |       |
| help_message | text        | NO   |     | NULL    |       |
+--------------+-------------+------+-----+---------+-------+</pre>
</blockquote>
<p>And a <strong>help()</strong> procedure, so that you can call for <em>help()</em>. The procedure will look for the best matching document based on your search expression:</p>
<blockquote>
<pre>root@mysql-5.1.51&gt; <strong>CALL help('match');</strong>
<strong>+---------------------------------------</strong>----------------------------------------+
| help                                                                          |
+-------------------------------------------------------------------------------+
|                                                                               |
| NAME                                                                          |
|                                                                               |
| match_grantee(): Match an existing account based on user+host.                |
|                                                                               |
| TYPE                                                                          |
|                                                                               |
| Function                                                                      |
|                                                                               |
| DESCRIPTION                                                                   |
|                                                                               |
| MySQL does not provide with identification of logged in accounts. It only     |
| provides with user + host:port combination within processlist. Alas, these do |
| not directly map to accounts, as MySQL lists the host:port from which the     |
| connection is made, but not the (possibly wildcard) user or host.             |
| This function matches a user+host combination against the known accounts,     |
| using the same matching method as the MySQL server, to detect the account     |
| which MySQL identifies as the one matching. It is similar in essence to       |
| CURRENT_USER(), only it works for all sessions, not just for the current      |
| session.                                                                      |
|                                                                               |
| SYNOPSIS                                                                      |
|                                                                               |
|                                                                               |
|                                                                               |
|        match_grantee(connection_user char(16) CHARSET utf8,                   |
|        connection_host char(70) CHARSET utf8)                                 |
|          RETURNS VARCHAR(100) CHARSET utf8                                    |
|                                                                               |
|                                                                               |
| Input:                                                                        |
|                                                                               |
| * connection_user: user login (e.g. as specified by PROCESSLIST)              |
| * connection_host: login host. May optionally specify port number (e.g.       |
|   webhost:12345), which is discarded by the function. This is to support      |
|   immediate input from as specified by PROCESSLIST.                           |
|                                                                               |
|                                                                               |
| EXAMPLES                                                                      |
|                                                                               |
| Find an account matching the given use+host combination:                      |
|                                                                               |
|                                                                               |
|        mysql&gt; SELECT match_grantee('apps', '192.128.0.1:12345') AS            |
|        grantee;                                                               |
|        +------------+                                                         |
|        | grantee    |                                                         |
|        +------------+                                                         |
|        | 'apps'@'%' |                                                         |
|        +------------+                                                         |
|                                                                               |
|                                                                               |
|                                                                               |
| ENVIRONMENT                                                                   |
|                                                                               |
| MySQL 5.1 or newer                                                            |
|                                                                               |
| SEE ALSO                                                                      |
|                                                                               |
| processlist_grantees                                                          |
|                                                                               |
| AUTHOR                                                                        |
|                                                                               |
| Shlomi Noach                                                                  |
|                                                                               |
+-------------------------------------------------------------------------------+</pre>
</blockquote>
<p>I like HTML for documentation. I think it's a good format, provided you don't start doing funny things. Perhaps <em>TROFF</em> is more suitable; certainly more popular on Unix machines. But I already have everything in HTML. So, what do I do?</p>
<p>My decision was to keep documentation in HTML, and use the handy <em>html2text</em> tool to do the job. And it does it pretty well! The sample you see above is an automated translation of HTML to plain text.</p>
<p>I add a few touches of my own: SELECTing long texts is ugly, whether you do it via "<strong>;</strong>" or "<strong>\G</strong>". The <strong>help()</strong> routine breaks the text by '<strong>\n</strong>', returning a multi row result set. The above sample makes for some <strong>60+</strong> rows, nicely formatted, broken from the original single text appearing in the <strong>help</strong> table.</p>
<p>So now you have an internal help method for <em>common_schema</em>, right where the code is. You don't have to leave the command line client in order to get help.</p>
<p><a href="http://datacharmer.blogspot.com/">Giuseppe</a> offered me the idea for this, even while my own thinking about it was in early stages.</p>
<p>The next version of <em>common_schema</em> will be available in a few weeks. The code is pretty much ready. I just need to work on, ahem..., the documentation.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/documentation-in-sql-call-for-help/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Oracle &quot;Technologist of the Year: Developer&quot; Award</title>
		<link>http://code.openark.org/blog/mysql/oracle-technologist-of-the-year-developer-award</link>
		<comments>http://code.openark.org/blog/mysql/oracle-technologist-of-the-year-developer-award#comments</comments>
		<pubDate>Wed, 21 Dec 2011 06:51:54 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[award]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Open Source]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4009</guid>
		<description><![CDATA[I am honored to receive Oracle's Technologist of the Year: Developer award, formerly Oracle Magazine Editors’ Choice Awards. Technologist of the Year Award is given for individuals for their technical achievements with regard to Oracle products. As opposed to community based awards, to win this award one must be nominated by himself or his company. [...]]]></description>
			<content:encoded><![CDATA[<p>I am honored to receive <a href="http://www.oracle.com/technetwork/issue-archive/2012/12-jan/o12awards-tech-1403083.html">Oracle's Technologist of the Year: Developer</a> award, formerly <em>Oracle Magazine</em> Editors’ Choice Awards.</p>
<p>Technologist of the Year Award is given for individuals for their technical achievements with regard to Oracle products.</p>
<p>As opposed to <a href="http://code.openark.org/blog/mysql/mysql-conference-2009-community-awards">community</a> based <a href="http://code.openark.org/blog/mysql/oracle-ace">awards</a>, to win this award one must be <a href="http://www.oracle.com/us/corporate/awards/technologist/index.html">nominated</a> by himself or his company. There are several award categories: Developer, DBA, IT Manager etc., and many nominations per category. I have been nominated by my company and am happy to have won the award in the Developer category.</p>
<p>Allow me to take the pleasant opportunity to make some acknowledgements.<span id="more-4009"></span></p>
<h4>makam</h4>
<p>Most people know me as a MySQL consultant/instructor/speaker/something. I wear several hats; in one I am co-founder and CTO of <strong>SFNK</strong>, an Israeli company providing the <strong>makam</strong> system, a specialized service providing valuable insight on our customers increasing need: the need to know what people say about them on the internet. Our product is running for <strong>7</strong> years now, is serving large amounts of data, and is operating several MySQL server nodes.</p>
<p>I've been working with MySQL for over <strong>11</strong> years, but it is throughout my work in <em>makam</em> that I have come to look deeply into query &amp; server optimization, backups, scale out, design etc. We had some demanding features that pushed me into developing scripts and solutions for MySQL, released as open source. Throughout my experience as a DBA (I'm originally a developer) I came to appreciate the MySQL product, on one had, and find usability fallacies, on the other. The fact that our product is DB centric put me in the position to learn as much as I could about SQL.</p>
<p>I thank <em>makam</em> for this. This product has been the test bed for many of my experiments. Thankfully I never erased the database!</p>
<h4>The MySQL community</h4>
<p>Though I just recently <a href="http://code.openark.org/blog/mysql/oracle-ace">wrote this</a>, I'm happy to acknowledge it again.</p>
<p>Since my work is based off open source products, open source projects, free advice, professional blogs, I have gained much from the open source world in general, and from the MySQL community in particular, that made me want to share some back.</p>
<p>Its wonderful to have people read and comment on my blog posts and ideas; download, use and provide feedback on code I write; attend an occasional talk. All this pushes me in my work. I honestly hope to have provided with valuable content, code or assistance, to just anyone. Anyone and someone who would benefit from the richness of open source and knowledge sharing.</p>
<p>I am humbled by the advantage I got from the community. I have found names behind the community's first anonymous appearance. I've found people who are easy to reach, happy to respond, generous in their advice, experts in their field.</p>
<p>Thank you.</p>
<h4>Oracle &amp; MySQL</h4>
<p>An observation on this award is that it is given to a MySQL technologist. I have never worked with Oracle (as in the RDBMS) technologies, and my entire nomination is based on my experience with MySQL.</p>
<p>I see significance in this, and believe it reaffirms the focus and attention MySQL gets from Oracle. It makes me happy as a MySQL user and as a MySQL community member.</p>
<p>I thank Oracle for giving me this honor.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/oracle-technologist-of-the-year-developer-award/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Monitor your MySQL servers as done before, for free!</title>
		<link>http://code.openark.org/blog/mysql/monitor-your-mysql-servers-as-done-before-for-free</link>
		<comments>http://code.openark.org/blog/mysql/monitor-your-mysql-servers-as-done-before-for-free#comments</comments>
		<pubDate>Sun, 18 Dec 2011 06:48:10 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4568</guid>
		<description><![CDATA[With genuine respect to other products, the people making those products and the efforts involved, I would like to make an issue: Some things have been done before, done pretty well (if I may say so), and for free. mycheckpoint is a free monitoring tool for MySQL. It uses an unorthodox approach of monitoring your [...]]]></description>
			<content:encoded><![CDATA[<p>With genuine respect to other <a href="http://www.webyog.com/blog/2011/12/16/monitor-your-mysql-servers-like-never-before-use-csos/">products</a>, the people making those products and the efforts involved, I would like to make an issue:</p>
<p>Some things <a href="http://code.openark.org/blog/mysql/mycheckpoint-rev-170-improved-custom-queries-local-charting-pageswap-io-monitoring-improved-html-reports">have been done before</a>, done pretty well (if I may say so), and for free.</p>
<p><a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a> is a free monitoring tool for MySQL. It uses an unorthodox approach of monitoring your MySQL servers by storing the monitored data in SQL format (actually, within a MySQL server). This allows you to either use the <a href="http://mycheckpoint.googlecode.com/svn/trunk/doc/html/sample/http/mcp_sql00/sv_report_html_brief">fancy JavaScript charting</a> (by running <em>mycheckpoint</em> as <a href="http://code.openark.org/forge/mycheckpoint/documentation/http-web-server">HTTP server</a>), or <a href="http://code.openark.org/forge/mycheckpoint/documentation/querying-for-data">Do-It-Yourself diagnostics</a>.</p>
<p>It allows for a great many more things, among which are <a href="http://code.openark.org/forge/mycheckpoint/documentation/custom-monitoring">custom queries and charts</a>: you may add your own queries, to be included in the monitoring scheme. Query your <strong>AUTO_INCREMENT</strong> values to detect growth rate, query your <strong>INFORMATION_SCHEMA</strong> tables (if you dare) to learn about your data dimensions, query for query response time to detect performance issues with your website/database, or query your data itself (e.g. <em>sales per day</em>) to get insight about your product. Here are <a href="http://mycheckpoint.googlecode.com/svn/trunk/doc/html/sample/http/mcp_sql00/sv_report_html_brief#Custom">sample charts</a> to illustrate.<span id="more-4568"></span></p>
<p>Adding a custom query is as easy as producing an <strong>INSERT</strong> command. And of course you can set up <a href="http://code.openark.org/forge/mycheckpoint/documentation/alerts">alert conditions</a>. You can set them up on your normal monitored data (e.g. <em>seconds behind master</em>) or on your custom monitored data (e.g. <em>time it takes to execute cart-items query is too long</em>, <em>rate of purchases is below some threshold</em> etc.). It works the same since all monitored data, standard &amp; custom, is stored in SQL format: rows, columns, a table.</p>
<p>This also means you can retroactively check for different thresholds; you can query your data anyway you like! mycheckpoint provides you with a good visualization tool, but, like a good command like client, leaves the data intact for you to analyze the way you like it.</p>
<p>Of course you can get <a href="http://code.openark.org/forge/mycheckpoint/documentation/emails">emailed</a> once an alert pops up. But wait, not so fast: you can ask the alert to pop up only if the threshold is trespassed for a <em>given amount of time</em>. For example, it may be OK for OS load average to increase for a few moments, but you may wish to be alerted if this happens for over <strong>30</strong> minutes continuously.</p>
<p>The thing is, you get all these in an uncompressed <strong>222K</strong> single python script (<strong>43K</strong> compressed), and there's no trial period. <em>mycheckpoint</em> is completely free to <a href="http://code.google.com/p/mycheckpoint/">download and use</a> under the <strong>BSD</strong> license. It is listed in <a href="http://www.infoworld.com/d/data-management/10-essential-mysql-tools-admins-168018">10 essential MySQL tools for admin</a>, and is <a href="http://code.openark.org/forge/mycheckpoint/documentation">well documented</a>.</p>
<p>I'm not suggesting the scope of <em>mycheckpoint</em> levels with that of other products. It is lightweight; it does not have the full featured web interface as others do; there's work to be done. It only provides basic OS monitoring, and there are missing parts, like replication topology monitoring. But it is feature rich. As the author of <em>mycheckpoint</em> I take notice of using it on production for my own servers. It gets the job done.</p>
<p>It uses some ideas based on existing tools, and a few original ones. Before you say <em>"like never before"</em>, take a look at <em>mycheckpoint</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/monitor-your-mysql-servers-as-done-before-for-free/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>INFORMATION_SCHEMA Optimizations: still crashing my servers</title>
		<link>http://code.openark.org/blog/mysql/information_schema-optimizations-still-crashing-my-servers</link>
		<comments>http://code.openark.org/blog/mysql/information_schema-optimizations-still-crashing-my-servers#comments</comments>
		<pubDate>Mon, 12 Dec 2011 07:35:19 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[INFORMATION_SCHEMA]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4561</guid>
		<description><![CDATA[[Update: need to take more breaks: now NOT crashing my servers! See clarifications below] INFORMATION_SCHEMA Optimizations are meant to make your INFORMATION_SCHEMA queries lighter and safer. For example, if you're going to query the COLUMNS table for just the columns of a single table, then the following: SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='sakila' AND TABLE_NAME='rental' [...]]]></description>
			<content:encoded><![CDATA[<p><strong>[Update</strong>: need to take more breaks: now<strong> NOT</strong> crashing my servers! See clarifications below<strong>]</strong></p>
<p><a href="http://dev.mysql.com/doc/refman/5.1/en/information-schema-optimization.html">INFORMATION_SCHEMA Optimizations</a> are meant to make your <strong>INFORMATION_SCHEMA</strong> queries lighter and safer.</p>
<p>For example, if you're going to query the <strong>COLUMNS</strong> table for just the columns of a single table, then the following:</p>
<blockquote>
<pre>SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='sakila' AND TABLE_NAME='rental'</pre>
</blockquote>
<p>makes for an optimization: specifying a literal on <strong>TABLE_SCHEMA</strong> avoid scanning the directories of other schemata. Specifying a literal on <strong>TABLE_NAME</strong> avoids checking up on other tables. So it's a one-schema-one-table read operation, as opposed to <em>"first read every single column from all and any single schema and table, then return only those I'm interested in"</em>.</p>
<p>Here's the execution plan for the above query:</p>
<blockquote>
<pre>*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: COLUMNS
         type: ALL
possible_keys: NULL
          key: TABLE_SCHEMA,TABLE_NAME
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Using where; Open_frm_only; Scanned 0 databases</pre>
</blockquote>
<p>What I tried to do is to read the entire <strong>COLUMNS</strong> table, one schema at a time, one table at a time. I'm good with this taking longer time.</p>
<p>I have a production system on which reads from <strong>COLUMNS</strong> <em>consistently crash the servers</em>. Well, one read at a time can't do harm, right?<span id="more-4561"></span></p>
<p><del>Unfortunately, as the title of this posts reveals, even sequential read of <strong>COLUMNS</strong> using <strong>INFORMATION_SCHEMA</strong> optimization does not help: a minute into the process and the client lost connection. The server crashed.</del></p>
<p><del>I was expecting that table locks would be released, buffers released etc. One at a time, there wouldn't be a congestion of locks, reads, table cache suffocation etc.</del></p>
<p><del>Was actually having high hopes for this to succeed. I have to find a way in which <strong>INFORMATION_SCHEMA</strong> tables are not dangerous.</del></p>
<p>A few hours later, and I have both conclusions and achievements.</p>
<p>There are indeed memory issues with querying from <strong>INFORMATION_SCHEMA</strong> tables. I've found that <strong>VARCHAR(64)</strong> columns can consume <strong>64K</strong> each: I'm reading from large tables of more than <strong>1,000</strong> columns each, while monitoring MySQL's memory consumption. By dividing the increase in memory by the number of rows resulting from a query I sent, and which was for one single columns, I got an almost exact <strong>64K</strong> value per row.</p>
<p>So a query on <strong>INFORMATION_SCHEMA</strong> consumes much more memory than it should. The good news is that this memory is released once the query terminates. So there is no leak into the session memory.</p>
<p>This is combined with a <em>mistake of mine</em> in the way I iterated the tables, such that the problem was amplified: I happened to query much more than I needed, and so got my query's memory bloated. That is to say, I used the <strong>INFORMATION_SCHEMA</strong> optimizations only partly right, and so got only part of the savings it could offer me.</p>
<p>With better pinpointing I'm now actually able to read from <strong>COLUMNS,</strong> without crashing my servers, <em>consistently</em>.</p>
<p>I will further look into the <strong>64K</strong> issue. That in itself still drains a lot of memory: on my <a href="http://code.openark.org/forge/mycheckpoint">mycheckpoint</a> schema tables a singe table read means &gt; <strong>64MB</strong> of query memory down the drain.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/information_schema-optimizations-still-crashing-my-servers/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>More MySQL foreach()</title>
		<link>http://code.openark.org/blog/mysql/more-mysql-foreach</link>
		<comments>http://code.openark.org/blog/mysql/more-mysql-foreach#comments</comments>
		<pubDate>Fri, 02 Dec 2011 13:55:32 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[common_schema]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[INFORMATION_SCHEMA]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4171</guid>
		<description><![CDATA[In my previous post I've shown several generic use cases for foreach(), a new scripting functionality introduced in common_schema. In this part I present DBA's handy syntax for schema and table operations and maintenance. Confession: while I love INFORMATION_SCHEMA's power, I just hate writing queries against it. It's just so much typing! Just getting the [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://code.openark.org/blog/mysql/mysql-foreach">previous post</a> I've shown several generic use cases for <a href="http://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/foreach.html"><em>foreach()</em></a>, a new scripting functionality introduced in <a href="http://code.google.com/p/common-schema/" rel="nofollow">common_schema</a>.</p>
<p>In this part I present DBA's handy syntax for schema and table operations and maintenance.</p>
<p>Confession: while I love <strong>INFORMATION_SCHEMA</strong>'s power, I just <em>hate</em> writing queries against it. It's just so much typing! Just getting the list of tables in a schema makes for this heavy duty query:</p>
<blockquote>
<pre>SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='sakila' AND TABLE_TYPE='BASE TABLE';</pre>
</blockquote>
<p>When a join is involved this really becomes a nightmare. I think it's cumbersome, and as result, many do not remember the names and meaning of columns, making for <em>"oh, I need to read the manual all over again just to get that query right"</em>. Anyway, that's my opinion.</p>
<p>A <strong>SHOW TABLES</strong> statement is easier to type, but cannot be integrated into a <strong>SELECT</strong> query (though <a href="http://code.openark.org/blog/mysql/reading-results-of-show-statements-on-server-side">we have a partial solution</a> for that, too), and besides, when filtering out the views, the <strong>SHOW</strong> statement becomes almost as cumbersome as the one on <strong>INFORMATION_SCHEMA</strong>.</p>
<p>Which is why <em>foreach()</em> offers handy shortcuts to common iterations on schemata and tables, as follows:</p>
<h4>Use case: iterate all databases</h4>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'schema'</span>, <span style="color: #003366;">'CREATE TABLE ${schema}.event(event_id INT, msg VARCHAR(128))'</span>);</pre>
</blockquote>
<p>In the above we execute a query on each database. Hmmm, maybe not such a good idea to perform this operation on all databases? Let's filter them:</p>
<h4>Use case: iterate databases by name match</h4>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'schema like wordpress_%'</span>, <span style="color: #003366;">'ALTER TABLE ${schema}.wp_posts MODIFY COLUMN comment_author VARCHAR(96) NOT NULL'</span>);</pre>
</blockquote>
<p>The above will only iterate my WordPress databases (I have several of these), performing an <strong>ALTER</strong> on <strong>wp_posts</strong> for each of those databases.<span id="more-4171"></span></p>
<p>I don't have to quote the <em>like</em> expression, but I can, if I wish to.</p>
<p>I can also use a regular expression match:</p>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'schema ~ /^wordpress_[0-9]+$/'</span>, <span style="color: #003366;">'ALTER TABLE ${schema}.wp_posts MODIFY COLUMN comment_author VARCHAR(96) NOT NULL'</span>);</pre>
</blockquote>
<h4>Use case: iterate tables in a specific schema</h4>
<p>Time to upgrade our <strong>sakila</strong> tables to InnoDB's compressed format. We use <strong>$()</strong>, a synonym for <em>foreach()</em>.</p>
<blockquote>
<pre>call $(<span style="color: #808000;">'table in sakila'</span>, <span style="color: #003366;">'ALTER TABLE ${schema}.${table} ENGINE=InnoDB ROW_FORMAT=COMPRESSED'</span>);</pre>
</blockquote>
<p>The above will iterate on tables in <strong>sakila</strong>. I say <em>tables</em>, since it will avoid iterating views (there is still no specific syntax for views iteration). This is done on purpose, as my experience shows there is very little in common between tables and views when it comes to maintenance and operations.</p>
<h4>Use case: iterate tables by name match</h4>
<p>Here's a interesting scenario: you wish to work on all tables matching some name. The naive approach would be to:</p>
<blockquote>
<pre>SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'wp_posts' AND TABLE_TYPE = 'BASE TABLE'</pre>
</blockquote>
<p><em><strong>Wait!</strong></em> Are you aware this may bring your server down? This query will open all databases at once, opening all <strong>.frm</strong> files (though thankfully not data files, since we only check for name and type).</p>
<p>Here's a better approach:</p>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'table like wp_posts'</span>, <span style="color: #003366;">'ALTER TABLE ${schema}.${table} ENGINE=InnoDB'</span>);</pre>
</blockquote>
<p>(There's now FULLTEXT to InnoDB, so the above can make sense in the near future!)</p>
<p>The good part is that <em>foreach()</em> will look for matching tables <em>one database at a time</em>. It will iterate the list of database, then look for matching tables per database, thereby optimizing the query on <strong>INFORMATION_SCHEMA</strong>.</p>
<p>Here, too, I can use regular expressions:</p>
<blockquote>
<pre>call $(<span style="color: #808000;">'table ~ /^wp_.*$/'</span>, <span style="color: #003366;">'ALTER TABLE ${schema}.${table} ENGINE=InnoDB'</span>);</pre>
</blockquote>
<h4>Conclusion</h4>
<p>This is work in the making, but, as someone who maintains a few productions servers, I've already put it to work.</p>
<p>I'm hoping the syntax is easy to comprehend. I know that since I developed it it must be far more intuitive to myself than to others. I've tried to keep close on common syntax and concepts from various programming languages.</p>
<p>I would like to get as much feedback as possible. I have further ideas and thoughts on the direction <a href="http://code.google.com/p/common-schema/">common_schema</a> is taking, but wish take it in small steps. Your feedback is appreciated!</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/more-mysql-foreach/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MySQL foreach()</title>
		<link>http://code.openark.org/blog/mysql/mysql-foreach</link>
		<comments>http://code.openark.org/blog/mysql/mysql-foreach#comments</comments>
		<pubDate>Fri, 02 Dec 2011 04:59:03 +0000</pubDate>
		<dc:creator>shlomi</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[common_schema]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://code.openark.org/blog/?p=4002</guid>
		<description><![CDATA[A new routine is now available in common_schema, which makes for an easier execution syntax for some operations: foreach(collection_to_iterate_over, queries_to_execute_per_iteration_step); To illustrate what it can do, consider: call foreach('table in sakila', 'ALTER TABLE ${schema}.${table} ENGINE=InnoDB ROW_FORMAT=COMPACT'); call $('schema like shard_%', 'CREATE TABLE ${schema}.messages (id INT)'); call $('2000:2009', 'INSERT IGNORE INTO report (report_year) VALUES (${1})'); $() [...]]]></description>
			<content:encoded><![CDATA[<p>A new routine is now available in <a href="http://code.google.com/p/common-schema/" rel="nofollow">common_schema</a>, which makes for an easier execution syntax for some operations:</p>
<blockquote>
<pre>foreach(<span style="color: #808000;"><em>collection_to_iterate_over</em></span>, <span style="color: #003366;"><em>queries_to_execute_per_iteration_step</em></span>);</pre>
</blockquote>
<p>To illustrate what it can do, consider:</p>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'table in sakila'</span>, <span style="color: #000080;">'ALTER TABLE <strong>${schema}</strong>.<strong>${table}</strong> ENGINE=InnoDB ROW_FORMAT=COMPACT'</span>);

call $(<span style="color: #808000;">'schema like shard_%</span>', <span style="color: #000080;">'CREATE TABLE <strong>${schema}</strong>.messages (id INT)'</span>);

call $(<span style="color: #808000;">'2000:2009'</span>, <span style="color: #000080;">'INSERT IGNORE INTO report (report_year) VALUES (<strong>${1}</strong>)'</span>);</pre>
</blockquote>
<p><strong>$()</strong> stands as a synonym to <em>foreach()</em>. I suspect it should look familiar to web programmers.</p>
<p>The idea for <em>foreach()</em> was introduced by Giuseppe Maxia during a correspondence. At first I was skeptic: this isn't <a href="http://api.jquery.com/jQuery.each/">jQuery</a>; this is SQL. Why would I want to use <em>foreach()</em>?</p>
<p>Then Giuseppe provided some use cases, and as I started thinking about it, I found more and more cases where such a tool might considerably reduce scripting overhead and avoid requiring SQL-fu skills. In fact, I have been using it myself for the past few weeks</p>
<p>I provide examples which I hope will convince the reader as for the simplicity of using such syntax. Showing off the types of input <em>foreach()</em> accepts (query, table search, schema search, set of constants, single or double numbers range), and the types of queries it can execute (single, multiple, using placeholders).</p>
<p>I stress that this is not a replacement for common queries (i.e. does <em>not</em> come to replace your common <strong>SELECT</strong>, <strong>UPDATE</strong>, <strong>DELETE</strong>), but more for working out administrative tasks. Nevertheless, the last example in this post does provide with an interesting insight on possible "normal" use.<span id="more-4002"></span></p>
<h4>Use case: using values from query</h4>
<p>Let's kill all queries running for over <strong>20</strong> seconds:</p>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'SELECT id FROM INFORMATION_SCHEMA.PROCESSLIST WHERE time &gt; 20'</span>, <span style="color: #000080;">'KILL QUERY <strong>${1}</strong>'</span>);</pre>
</blockquote>
<p>The thing I like most about <em>foreach()</em> is that it's self explanatory. Nevertheless, I note:</p>
<ul>
<li>The <strong>KILL</strong> command is executed for each process running for more than <strong>20</strong> seconds (I did round up corners, since I didn't check for sleeping processes, for simplicity).</li>
<li>I also use the <strong>${1}</strong> placeholder: much like in <em>awk</em>, this will get the first column in the result set. In our case, it is the single column, <strong>id</strong>.</li>
<li>I chose to invoke a single query/command per iteration step.</li>
</ul>
<p>Compare the above with another solution to the same problem, using <a href="http://code.openark.org/blog/mysql/mysql-eval">eval()</a>:</p>
<blockquote>
<pre>call eval('SELECT CONCAT(\'KILL QUERY \',id) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE TIME &gt; 20');</pre>
</blockquote>
<p>They both get the same thing done. But <em>foreach()</em> is just a bit more friendly to write (and read).</p>
<p>Let's move to a more complicated example.</p>
<h4>Use case: using multiple values from a query, invoking multiple commands</h4>
<p>Let's kill some queries, as above, but also write down a log entry so that we know what happened:</p>
<blockquote>
<pre>call foreach(
  <span style="color: #808000;">'SELECT id, user FROM INFORMATION_SCHEMA.PROCESSLIST WHERE time &gt; 20'</span>,
  <span style="color: #000080;">'KILL QUERY <strong>${1}</strong>; INSERT INTO my_log VALUES (\'have just killed query <strong>${1}</strong>, executed by <strong>${2}</strong>\');'</span>)
;</pre>
</blockquote>
<p>In the above, for each long running process, we:</p>
<ul>
<li>Kill the process' query. <strong>id</strong> being the first column, is referenced by <strong>${1}</strong>.</li>
<li>INSERT to my_log that said process has been killed. We note both <strong>id</strong> and <strong>user</strong> using placeholders <strong>${1}</strong> and <strong>${2}</strong>, respectively.</li>
</ul>
<p>It's possible to invoke as many queries/commands per iteration step. It is possible to use placeholders <strong>${1}</strong> through <strong>${9}</strong>, as well as <strong>${NR}</strong>, which works as in <em>awk</em>: it is a row-counter, <strong>1</strong>-based.</p>
<p>This example can still be written with <em>eval()</em>, but in much uglier form. I can't just first <strong>KILL</strong> the processes, then log about them, since by the time I want to log, the queries will not be running; the commands <em>must be coupled</em>. This is naturally done with <em>foreach()</em>.</p>
<h4>Use case: iterating constant values, invoking DDL</h4>
<p>The commands invoked by <em>foreach()</em> can take the form of DML (<strong>INSERT</strong>/<strong>UPDATE</strong>/...), DDL (<strong>CREATE</strong>/<strong>ALTER</strong>/...) or other (<strong>KILL</strong>/<strong>SET</strong>/...). The placeholders can be used anywhere within the text.</p>
<p>Take an installation where different schemata have the same exact table structure. We want to refactor a table on all schemata:</p>
<blockquote>
<pre>call $(<span style="color: #808000;">'<strong>{USA, UK, Japan, NZ}</strong>'</span>, <span style="color: #000080;">'ALTER TABLE db_region_<strong>${1}</strong>.customer ADD COLUMN personal_notes VARCHAR(4096) CHARSET utf8'</span>);</pre>
</blockquote>
<p>The above translates to the following commands:</p>
<blockquote>
<pre>ALTER TABLE <strong>db_region_USA</strong>.customer ADD COLUMN personal_notes VARCHAR(4096) CHARSET utf8;
ALTER TABLE <strong>db_region_UK</strong>.customer ADD COLUMN personal_notes VARCHAR(4096) CHARSET utf8;
ALTER TABLE <strong>db_region_Japan</strong>.customer ADD COLUMN personal_notes VARCHAR(4096) CHARSET utf8;
ALTER TABLE <strong>db_region_NZ</strong>.customer ADD COLUMN personal_notes VARCHAR(4096) CHARSET utf8;</pre>
</blockquote>
<p>In the above, we:</p>
<ul>
<li>Provide a list of constant values. These can be strings, numbers, whatever. They are space delimited.</li>
<li>Use the <strong>${1}</strong> place holder. We can also use <strong>${NR}</strong>.</li>
</ul>
<h4>Use case: loop through number sequence</h4>
<p>We wish to populate a table with values:</p>
<blockquote>
<pre>call foreach(<span style="color: #808000;">'<strong>1970:2038</strong>'</span>, <span style="color: #003366;">'INSERT INTO test.test_dates (dt) VALUES (DATE(\'<strong>${1}</strong>-01-01\'))'</span>);</pre>
</blockquote>
<p>The above results with:</p>
<blockquote>
<pre>mysql&gt; SELECT dt FROM test_dates;
+------------+
| dt         |
+------------+
| 1970-01-01 |
| 1971-01-01 |
| 1972-01-01 |
| 1973-01-01 |
| 1974-01-01 |
...
| 2036-01-01 |
| 2037-01-01 |
| 2038-01-01 |
+------------+</pre>
</blockquote>
<p>With numbers range:</p>
<ul>
<li>Integers are assumed</li>
<li>Range is indicated by low and high values, both inclusive</li>
<li>Negatives allowed (e.g. <strong>'-5:5'</strong>, resulting with <strong>11</strong> steps)</li>
<li>Placeholders <strong>${1}</strong> and <strong>${NR}</strong> are allowed.</li>
</ul>
<h4>Use case: iterating through two dimensional numbers range:</h4>
<p>We use <strong>3</strong> template tables; we create <strong>15</strong> schemata; in each we create <strong>3</strong> tables based on the template tables:</p>
<blockquote>
<pre>call foreach(<span style="color: #808000;"><strong> '1:15,1:3'</strong></span>,
  <span style="color: #003366;">'CREATE DATABASE IF NOT EXISTS db_test_${1}; CREATE TABLE db_test_${1}.tbl_${2} LIKE db_template.my_table_${2};'</span>
);</pre>
</blockquote>
<p>Notes:</p>
<ul>
<li>Each of the number ranges has the same restrictions and properties as listed above (integers, inclusive, ascending)</li>
<li>We can now use <strong>${1}</strong> and <strong>${2}</strong> placeholders, noting the first and second numbers range, respectively.</li>
<li>We may also use <strong>${NR}</strong>, which, in this case, will run <strong>1</strong> through <strong>45</strong> (<strong>15</strong> times <strong>3</strong>).</li>
<li>We use multiple queries per iteration step.</li>
</ul>
<h4>Use case: overcoming MySQL limitations</h4>
<p>MySQL does not support <strong>ORDER BY</strong> &amp; <strong>LIMIT</strong> in multi-table <strong>UPDATE</strong> and <strong>DELETE</strong> statements (as noted <a href="http://code.openark.org/blog/mysql/three-wishes-for-a-new-year">last year</a>). So we <em>cannot</em>:</p>
<blockquote>
<pre>DELETE FROM t1 USING t1 JOIN t2 ON (...) JOIN t3 ON (..) WHERE x = 7 ORDER BY ts LIMIT 100;</pre>
</blockquote>
<p>However, we <em>can</em>:</p>
<blockquote>
<pre>call foreach(
  <span style="color: #808000;">'SELECT t1.id FROM t1 JOIN t2 ON (...) JOIN t3 ON (..) WHERE x = 7 ORDER BY ts LIMIT 100'</span>,
  <span style="color: #003366;">'DELETE FROM t1 WHERE id = ${1}'</span>
);</pre>
</blockquote>
<p>Of course, it will do a lot of single row <strong>DELETE</strong>s. There are further MySQL limitations which complicate things if I want to overcome this. Perhaps at a later blog post.</p>
<h4>Acknowledgements</h4>
<p>I hit a weird <a href="http://bugs.mysql.com/bug.php?id=62406">bug</a> which prevented me from releasing this earlier on. Actually it's a duplicate of <a href="http://bugs.mysql.com/bug.php?id=12257">this bug</a>, which makes it <strong>6</strong> years old. Hurray.</p>
<p>To the rescue came <a href="http://rpbouman.blogspot.com/">Roland Bouman</a>, who suggested an idea so crazy even I was skeptic: to parse and modify the original query so as to rename column names according to my scheme. And of course he made it happen, along with some additional very useful stuff. It's really a <em>super-ultra-meta-meta-sql-fu</em> magic he does there.</p>
<p>So, thanks, Roland, for joining the ride, and thanks, Giuseppe, for testing and helping out to shape this functionality. It's great fun working with other people on open-source -- a new experience for me.</p>
<h4>Continued</h4>
<p>In this post I've covered the general-purpose iterations. There are also more specific types of iterations with <em>foreach()</em>. <a href="http://code.openark.org/blog/mysql/more-mysql-foreach">Continued next</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.openark.org/blog/mysql/mysql-foreach/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<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>
	</channel>
</rss>

