<?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>Laughing Meme &#187; mysql</title>
	<atom:link href="http://laughingmeme.org/tag/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://laughingmeme.org</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Sun, 29 Jan 2012 21:54:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>mySQL DBA: Cassandra is my NoSQL solution but..</title>
		<link>http://laughingmeme.org/2010/03/26/mysql-dba-cassandra-is-my-nosql-solution-but/</link>
		<comments>http://laughingmeme.org/2010/03/26/mysql-dba-cassandra-is-my-nosql-solution-but/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 20:33:47 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[cassandra]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/?p=4532</guid>
		<description><![CDATA[Enjoying reading Dathan&#8217;s take on Cassandra]]></description>
			<content:encoded><![CDATA[<p>Enjoying reading Dathan&#8217;s take on Cassandra</p>
<p><a href='http://mysqldba.blogspot.com/2010/03/cassandra-is-my-nosql-solution-but.html'>http://mysqldba.blogspot.com/2010/03/cassandra-is-my-nosql-solution-but.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2010/03/26/mysql-dba-cassandra-is-my-nosql-solution-but/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8220;Normalization is for sissies&#8221; will never work!</title>
		<link>http://laughingmeme.org/2010/01/30/normalization-is-for-sissies-will-never-work/</link>
		<comments>http://laughingmeme.org/2010/01/30/normalization-is-for-sissies-will-never-work/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:54:34 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[conventional wisdom]]></category>
		<category><![CDATA[flickr]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[normalization]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/?p=4449</guid>
		<description><![CDATA[Found this Kottke post from 2004, quoting Cal&#8217;s original (I think) &#8220;normalization is for sisses&#8221; talk. Love reading through the comments on that post patiently explaining how it will never work!]]></description>
			<content:encoded><![CDATA[<p>Found this Kottke post from 2004, quoting Cal&#8217;s original (I think) &#8220;normalization is for sisses&#8221; talk.  Love reading through the comments on that post patiently explaining how it will never work!</p>
<p><a href='http://kottke.org/04/10/normalized-data'>http://kottke.org/04/10/normalized-data</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2010/01/30/normalization-is-for-sissies-will-never-work/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>4294967295 and MySQL INT(20) Syntax Blows</title>
		<link>http://laughingmeme.org/2010/01/24/4294967295-and-mysql-int20-syntax-blows/</link>
		<comments>http://laughingmeme.org/2010/01/24/4294967295-and-mysql-int20-syntax-blows/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 06:01:39 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[big numbers]]></category>
		<category><![CDATA[flickr]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/?p=4412</guid>
		<description><![CDATA[When you&#8217;ve been working with a technology for a long time, it&#8217;s difficult not to develop Stockholm syndrome. Not sure when I started using MySQL, but I bought my first license in 1998. I think it wasn&#8217;t until mid-to-late &#8217;98 when we had to call Monty long distance to Sweden to get help with some [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/pjern/1339311643/"><img src="http://farm2.static.flickr.com/1156/1339311643_3acb54e40a.jpg" alt="Big Numbers 2 by pjern." title="" width="500" height="332" border="0"></a></p>

<p>When you&#8217;ve been working with a technology for a long time, it&#8217;s difficult not to develop Stockholm syndrome.  Not sure when I started using MySQL, but I bought my first license in 1998.   I think it wasn&#8217;t until mid-to-late &#8217;98 when we had to call <a href="http://monty-says.blogspot.com/">Monty</a> long distance to Sweden to get help with some tricky issues.  Which is to say its been a long time since I thought about how confusing MySQL&#8217;s CREATE TABLE syntax can be.</p>

<p>Which is not to say that the documentation isn&#8217;t clear:</p>

<blockquote>
  <p><em class="replaceable"><code>M</code></em> indicates the maximum display width for integer types. The maximum legal display width is 255.
  Display width is unrelated to the range of values a type can contain, as described in <a href="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html" title="10.2. Numeric Types">Section 10.2, “Numeric Types”</a>. For floating-point and fixed-point types, <em class="replaceable"><code>M</code></em> is the total number of digits that can be stored.</p>
</blockquote>

<p>But last week Flickr had a hiccup.  We hit <a href="http://www.flickr.com/photos/oming91745/4294967295/">4,294,967,295</a> photos. Or as a geek might say it, the largest number that can be represented by a 32-bit unsigned integer.  This didn&#8217;t exactly catch us by surprise.  We&#8217;d switched to using 64-bit ids for some things January, Friday the 13th, 2006.  That and we got bit a few years ago when we hit 2,147,483,647 photos (that&#8217;d be the max signed 32 bit integer).  Shortly after that we did a full audit of our tables.</p>

<p>But somehow we went on writing code after that, and we managed to slip a couple of new tables into the mix.  And some of those tables ended up with <code>INT(20)</code> columns.  Which simply mean we were adding some non-significant zeros to pad the display but truncating photo ids over 4294967295.</p>

<p>INT(5), INT(10), INT(20), and INT(255) all store the same amount of data.</p>

<p>Funny thing is, when I told this story to folks last week, this caught them by surprise.  Sophisticated engineers, some of whom had deployed quite large MySQL backed sites. Because they were right, that syntax is dumb. And confusing.  And I&#8217;d been taking it for granted so long I hadn&#8217;t thought about it in a decade.  Which is why I&#8217;d bother to write a blog post about a popular piece of software, behaving exactly as it&#8217;s extensively documented to work. </p>

<p>Also, it&#8217;s interesting to note how if you keep making the same mistakes they become easier and easier to fix.</p>

<p>If you&#8217;re ever debugging a problem and you see the number 42-mumble-mumble-mumble-7295 you&#8217;ve run out of 32-bit storage.
If you see 2-mumble-mumble-mumble-647 (2147483647) you&#8217;ve run out of signed 32-bit storage.
167-mumble-mumble-15 (16777215) you&#8217;ve run out of 24-bits
and 65-mumble-mumble-35 (65535) you&#8217;ve run out of 16-bits of integers.</p>

<p>Somehow those numbers just jump out at me after all this time, you ignore the numbers in the middle, and notice the significant bits at the front and the end.</p>

<p>Photo from <a href="http://www.flickr.com/photos/pjern/">pjern</a></p>
]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2010/01/24/4294967295-and-mysql-int20-syntax-blows/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Jzawodny: Dumber is Faster</title>
		<link>http://laughingmeme.org/2008/08/24/jzawodny-dumber-is-faster/</link>
		<comments>http://laughingmeme.org/2008/08/24/jzawodny-dumber-is-faster/#comments</comments>
		<pubDate>Sun, 24 Aug 2008 19:34:47 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[backfill backfill backfill]]></category>
		<category><![CDATA[beyond lamp]]></category>
		<category><![CDATA[log oreinted data]]></category>
		<category><![CDATA[megadata]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[post relational]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/?p=4007</guid>
		<description><![CDATA[We use this pattern so often we have libraries to make it easier.]]></description>
			<content:encoded><![CDATA[<p><a href="http://flickr.com">We</a> use this pattern so often we have <a href="http://flickr.com/search/?q=flickrhq%20backfill&amp;w=all&amp;m=tags">libraries</a> to make it easier.</p>
<p><a href='http://jeremy.zawodny.com/blog/archives/010523.html'>http://jeremy.zawodny.com/blog/archives/010523.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2008/08/24/jzawodny-dumber-is-faster/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>InnoDB 1.0: &#8220;Fast index creation: add or drop indexes without copying the data&#8221;</title>
		<link>http://laughingmeme.org/2008/04/16/innodb-10-fast-index-creation-add-or-drop-indexes-without-copying-the-data/</link>
		<comments>http://laughingmeme.org/2008/04/16/innodb-10-fast-index-creation-add-or-drop-indexes-without-copying-the-data/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 14:57:38 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[go fast now]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/?p=3801</guid>
		<description><![CDATA[Because the write locking happens at data copy time. If this pans out looks like they&#8217;ll have managed to stay focused post-Oracle acquisition.]]></description>
			<content:encoded><![CDATA[<p>Because the write locking happens at data copy time.  If this pans out looks like they&#8217;ll have managed to stay focused post-Oracle acquisition.</p>
<p><a href='http://www.innodb.com/innodb_plugin/features/'>http://www.innodb.com/innodb_plugin/features/</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2008/04/16/innodb-10-fast-index-creation-add-or-drop-indexes-without-copying-the-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mySQL DBA: MAJOR Problems in mysql-5.0.51</title>
		<link>http://laughingmeme.org/2008/01/14/mysql-dba-major-problems-in-mysql-5051/</link>
		<comments>http://laughingmeme.org/2008/01/14/mysql-dba-major-problems-in-mysql-5051/#comments</comments>
		<pubDate>Mon, 14 Jan 2008 19:41:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[scalability]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/2008/01/14/mysql-dba-major-problems-in-mysql-5051/</guid>
		<description><![CDATA[See also DO NOT USE O_DIRECT with EXT3]]></description>
			<content:encoded><![CDATA[<p>See also <a href="http://mysqldba.blogspot.com/2008/01/do-not-use-odirect-with-ext3.html">DO NOT USE O_DIRECT with EXT3</a></p>
<p><a href='http://mysqldba.blogspot.com/2008/01/major-problems-in-mysql-5051.html'>http://mysqldba.blogspot.com/2008/01/major-problems-in-mysql-5051.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2008/01/14/mysql-dba-major-problems-in-mysql-5051/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>John Allspaw: Capacity Planning for LAMP talk at MySQL Conf 2007</title>
		<link>http://laughingmeme.org/2007/04/27/john-allspaw-capacity-planning-for-lamp-talk-at-mysql-conf-2007/</link>
		<comments>http://laughingmeme.org/2007/04/27/john-allspaw-capacity-planning-for-lamp-talk-at-mysql-conf-2007/#comments</comments>
		<pubDate>Fri, 27 Apr 2007 17:02:55 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[talks]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[capacity]]></category>
		<category><![CDATA[flickr]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[slides]]></category>

		<guid isPermaLink="false">http://laughingmeme.org/2007/04/27/john-allspaw-capacity-planning-for-lamp-talk-at-mysql-conf-2007/</guid>
		<description><![CDATA[John is God at this stuff.]]></description>
			<content:encoded><![CDATA[<p>John is God at this stuff.</p>
<p><a href='http://www.kitchensoap.com/2007/04/27/slides-from-capacity-planning-for-lamp-talk-at-mysql-conf-2007/'>http://www.kitchensoap.com/2007/04/27/slides-from-capacity-planning-for-lamp-talk-at-mysql-conf-2007/</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2007/04/27/john-allspaw-capacity-planning-for-lamp-talk-at-mysql-conf-2007/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL DBA &#8211; notes from the flickr database wars</title>
		<link>http://laughingmeme.org/2006/07/31/mysql-dba-notes-from-the-flickr-database-wars/</link>
		<comments>http://laughingmeme.org/2006/07/31/mysql-dba-notes-from-the-flickr-database-wars/#comments</comments>
		<pubDate>Tue, 01 Aug 2006 03:48:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[flickr]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=3417</guid>
		<description><![CDATA[aka Dathan&#8217;s blog]]></description>
			<content:encoded><![CDATA[<p>aka Dathan&#8217;s blog </p>
<p><a href='http://mysqldba.blogspot.com/'>http://mysqldba.blogspot.com/</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2006/07/31/mysql-dba-notes-from-the-flickr-database-wars/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>First Innobase, and now Sleepy Cat?</title>
		<link>http://laughingmeme.org/2006/02/14/first-innobase-and-now-sleepy-cat/</link>
		<comments>http://laughingmeme.org/2006/02/14/first-innobase-and-now-sleepy-cat/#comments</comments>
		<pubDate>Tue, 14 Feb 2006 22:01:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=3252</guid>
		<description><![CDATA[Oracle is making a serious play to either get into the open source DB space&#8230; or to destroy it. Does MySQL have a transactional backend left that Oracle doesn&#8217;t own?]]></description>
			<content:encoded><![CDATA[<p>Oracle is making a serious play to either get into the open source DB space&#8230; or to destroy it.  Does MySQL have a transactional backend left that Oracle doesn&#8217;t own? </p>
<p><a href='http://news.com.com/2100-7344_3-6039070.html'>http://news.com.com/2100-7344_3-6039070.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2006/02/14/first-innobase-and-now-sleepy-cat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Xpath support coming in MySQL 5.1</title>
		<link>http://laughingmeme.org/2006/01/17/xpath-support-coming-in-mysql-51/</link>
		<comments>http://laughingmeme.org/2006/01/17/xpath-support-coming-in-mysql-51/#comments</comments>
		<pubDate>Tue, 17 Jan 2006 17:53:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=3191</guid>
		<description><![CDATA[plus cron-esque features. The rate of development on MySQL was gone from glacial to head spinning.]]></description>
			<content:encoded><![CDATA[<p>plus cron-esque features.  The rate of development on MySQL was gone from glacial to head spinning.</p>
<p><a href='http://jystewart.net/process/archives/2006/01/mysql-51/'>http://jystewart.net/process/archives/2006/01/mysql-51/</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2006/01/17/xpath-support-coming-in-mysql-51/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flushing Rails Database (MySQL) Sessions</title>
		<link>http://laughingmeme.org/2005/12/07/flushing-rails-database-mysql-sessions/</link>
		<comments>http://laughingmeme.org/2005/12/07/flushing-rails-database-mysql-sessions/#comments</comments>
		<pubDate>Wed, 07 Dec 2005 21:40:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[cron]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[typo]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=3146</guid>
		<description><![CDATA[I use Rails&#8217; database session backend for LM. (for login, as well as &#8220;flash&#8221;) Without any sort of built in garbage collection the sessions table gets very large, very quickly. Beyond aesthetic issues, this can also cause MySQL&#8217;s key buffer to fill up. (which on Debian is by default set quite low) So I wrote [...]]]></description>
			<content:encoded><![CDATA[<p>I use Rails&#8217; <a href="http://wiki.rubyonrails.com/rails/pages/HowtoChangeSessionStore">database session backend</a> for <a href="http://laughingmeme.org">LM</a>. (for login, as well as <a href="http://api.rubyonrails.com/classes/ActionController/Flash.html">&#8220;flash&#8221;</a>)  Without any sort of built in garbage collection the sessions table gets <strong>very</strong> large, very quickly.  Beyond aesthetic issues, this can also cause MySQL&#8217;s key buffer to fill up. (which on Debian is by default set quite low)</p>

<p>So I wrote up a quick flush method, and saved it in a file <code>models/session.rb</code>.</p>

<pre><code>class CGI::Session::ActiveRecordStore::Session
  def self.flush_old_empty_sessions
     self.delete_all "DATE_SUB(NOW(),INTERVAL 6 HOUR) &gt; 
     updated_at and BIT_LENGTH(data) &lt;= 688"
  end
end
</code></pre>

<p>This says nuke all sessions which are over 6 hours old, and which are empty.  (688 is the length of the serialized session with an empty flash)</p>

<p>MySQL specific, and susceptible to changes in either session structure or its serialization.  But it was quick and easy and worked for me.</p>

<p>Then you simply need a cron job like: <code>ruby script/runner  'CGI::Session::ActiveRecordStore::Session.flush_old_empty_sessions'</code></p>
]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2005/12/07/flushing-rails-database-mysql-sessions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#8220;Paris killed Achilles, remember, but Troy still lost.&#8221;</title>
		<link>http://laughingmeme.org/2005/10/11/paris-killed-achilles-remember-but-troy-still-lost/</link>
		<comments>http://laughingmeme.org/2005/10/11/paris-killed-achilles-remember-but-troy-still-lost/#comments</comments>
		<pubDate>Tue, 11 Oct 2005 20:48:55 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[quotable]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=3047</guid>
		<description><![CDATA[Best commet yet on the Oracle/InnoDB/MySQL store. Yay for squeezing every ounce of meaning out of a metaphor.]]></description>
			<content:encoded><![CDATA[<p>Best commet yet on the Oracle/InnoDB/MySQL store.  Yay for squeezing every ounce of meaning out of a metaphor.</p>
<p><a href='http://radar.oreilly.com/archives/2005/10/your_money_or_your_mysql.html'>http://radar.oreilly.com/archives/2005/10/your_money_or_your_mysql.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2005/10/11/paris-killed-achilles-remember-but-troy-still-lost/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building DBD::mysql on RH9:  &#8220;unset LANG; perl Makefile.PL; make test; make install&#8221;</title>
		<link>http://laughingmeme.org/2004/09/06/building-dbdmysql-on-rh9-unset-lang-perl-makefilepl-make-test-make-install/</link>
		<comments>http://laughingmeme.org/2004/09/06/building-dbdmysql-on-rh9-unset-lang-perl-makefilepl-make-test-make-install/#comments</comments>
		<pubDate>Tue, 07 Sep 2004 01:49:03 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[redhat]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=2515</guid>
		<description><![CDATA[RedHat sucks.]]></description>
			<content:encoded><![CDATA[<p>RedHat sucks.</p>
<p><a href='http://forums.devshed.com/archive/t-155739'>http://forums.devshed.com/archive/t-155739</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2004/09/06/building-dbdmysql-on-rh9-unset-lang-perl-makefilepl-make-test-make-install/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Package Surgery</title>
		<link>http://laughingmeme.org/2004/08/16/package-surgery/</link>
		<comments>http://laughingmeme.org/2004/08/16/package-surgery/#comments</comments>
		<pubDate>Mon, 16 Aug 2004 18:43:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[debian]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php5]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=885</guid>
		<description><![CDATA[I&#8217;ve started putting together Debian packages for our dev platform at work, and stumbled upon an obvious, and yet new to me technique for building quick and dirty .debs &#8230; package surgery. I&#8217;ve got a MySQL 4.1.3 package (an official package won&#8217;t be showing up anytime soon is the rumor) by the simple expedient of [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve started putting together Debian packages for our dev platform at work, and stumbled upon an obvious, and yet new to me technique for building quick and dirty .debs &#8230; package surgery.  I&#8217;ve got a MySQL 4.1.3 package (an official package won&#8217;t be showing up anytime soon is the rumor) by the simple expedient of downloading the 4.1.3 source from MySQL.com, and copying over the debian directory from the <a href="http://packages.debian.org/testing/misc/mysql-server">official package</a>.  Similarly a PHP 5.0.1 package that is compatible with Apache2 (apache2-mpm-prefork) is available by downloading <a href="http://www.dotdeb.org/">DotDeb&#8217;s</a> php5 package, and tweaking its debian/rules file. (rumor has it an official one of these might show up soon-ish)</p>

<p>Both are still pretty rough around the edges (I&#8217;m having trouble with config files not being installed, and not being updated properly), but hopefully in the next few days they&#8217;ll be available to a few brave souls.  (Though they already install pretty cleanly on an up-to-date sarge)</p>

<p>In the mean time, anyone know where I can find instructions on setting up an apt source?</p>
]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2004/08/16/package-surgery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL, and the CASE for Class Table Inheritance</title>
		<link>http://laughingmeme.org/2004/08/14/mysql-and-the-case-for-class-table-inheritance/</link>
		<comments>http://laughingmeme.org/2004/08/14/mysql-and-the-case-for-class-table-inheritance/#comments</comments>
		<pubDate>Sun, 15 Aug 2004 01:08:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[case]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[eaa]]></category>
		<category><![CDATA[enterprise]]></category>
		<category><![CDATA[Longer]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[patterns]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=883</guid>
		<description><![CDATA[At work we&#8217;re using Class Table Inheritance to model the core data structures of our as yet nameless open source CRM. (actually it has a code name, but I don&#8217;t like it, so we&#8217;ll pretend it&#8217;s nameless) This week as I learned both the name of this pattern, and the SQL to implement it efficiently [...]]]></description>
			<content:encoded><![CDATA[<p>
At <a href="http://groundspring.org">work</a> we&#8217;re using <a href="http://martinfowler.com/eaaCatalog/classTableInheritance.html">Class Table Inheritance</a> to model the core data structures of our as yet nameless open source <acronym title="Community Relationship Management">CRM</acronym>. (actually it has a code name, but I don&#8217;t like it, so we&#8217;ll pretend it&#8217;s nameless)  
</p>

<p><p>
This week as I learned both the name of this pattern, and the SQL to implement it efficiently in MySQL I thought I&#8217;d share some notes on what we&#8217;ve come up with.
</p>
<span id="more-883"></span>
<p>
<h3>Class Table Inheritance</h3>
<acronym title="Class Table Inheritance">CTI</acronym> is a pattern where your schema  hews closely to the your class hierarchy &#8212; you have a table for each class, and object attributes are stored as columns in the table for that class.  This is as opposed to <a href="http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html">Single Table Inheritance</a>, which stores all attributes for every member of an inheritance tree in a single table, or <a href="http://www.martinfowler.com/eaaCatalog/concreteTableInheritance.html">Concrete Table Inheritance</a> which duplicates the inherited fields to each table.
</p>
<p>
We&#8217;re using CTI for a number of reasons, some excellent, and some because that is how our brains work.  One key benefit is we get the ability to operate on heterogenous collections of object. (i.e. display a sorted list of contact objects irrespective of whether they are individuals, organizations, etc.)  The fact that something as fundamental as polymorphism can be difficult to accomplish using other O/R techniques hilights the general difficulty and <a href="http://www.google.com/search?q=impedance+mismatch" title="6 of the first 10 results are about O/R">impedance mismatch</a> of object to relational mapping.
</p>
<p>
There are, however a few challenges involved. 
</p>
<p>
<h3>The Model</h3>
But quickly a trivial mock up of the data model to give us something to play with.  In this model we have 3 classes, a base Contact class, and 2 types of contacts Individual and Organization which inherit from Contact.  In the database we model this as a Contact table, with a primary id, and any fields which the Contact the parent class provides.  Individual and Organization each get their own table, with class specific attributes, plus the primary id from Contact which is both the primary id, and a foreign key into Contact.  For every contact stored in the database there is a record in the Contact table, and a record in either Individual or Organization.
</p>
<p>
<img src="http://laughingmeme.org/img/simple_contact_model.gif" />
</p>
<p>
<h3>Challenge 1:</h3>
How do you retrieve your data now that it is broken across multiple tables?  The obvious (and obviously wrong) solution would be to first select against the Contact table, examine the resulting data, and select against the appropriate children tables. (remember this example is a drastically simplified data model)
</p>
<p>
<h3>Solution 1:</h3>
My current solution is to do a 3 way left outer join, and then instantiate the objects out of fields which aren&#8217;t null.  It can look a bit ugly with large numbers of columns, but is actually pretty simple, and initial benchmarks against a test data set of 1.3 million records suggests it scales nicely.</p>

<pre>
SELECT 
  c.id as id, c.contactType,
  i.firstName, i.lastName,
  o.name as orgName
FROM
  Contact as c
LEFT JOIN Individual as i ON i.id = c.id 
LEFT JOIN Organization as o ON o.id = c.id
</pre>

<p>(And it&#8217;s pretty easy to coax the necessary SQL out of our modified version of <a href="http://pear.php.net/package/DB_DataObject">DB_DataObject</a>. I&#8217;ll demonstrate that in a future entry)
</p>
<p>
<h3>Challenge 2:</h3>
One of the good reasons (in fact the only concrete one I&#8217;ve given you) to go with CTI and its potential added complexity is the desire to sort a mixed list of contact types.   But what do you do when you want to sort on an amorphous concept like &#8220;Name&#8221;?  Individual might sort by &#8220;Lastname, Firstname&#8221;, while we just use &#8220;orgName&#8221; for an organization.  Where is our polymorphism now?
</p>
<p>
One solution would be select all known records, and do sorting and slicing at the application level.  (This is so wrong it makes my head hurt)  Another solution would be store a field like &#8220;sortName&#8221; on Contact, which you could calculate and save on inserts and updates.  This is on the right track.
</p>
<p>
<h3>Solution 2:</h3>
The solution (which <a href="http://blogs.onenw.org/carl">Carl</a> clued me into while we waited to get into the zoo), is to use the <a href="http://dev.mysql.com/doc/mysql/en/Control_flow_functions.html">SQL CASE statement</a> to calculate &#8220;sortName&#8221; on the fly.  Below is our SQL from below with the new logic in green.</p>

<pre>
SELECT 
  c.id as id, c.contactType,
  i.firstName, i.lastName,
  o.name as orgName<span style="color:green;">,
CASE 
 WHEN c.contactType = 'Individual' THEN CONCAT(i.lastName, i.firstName)
 WHEN c.contactType = 'Organization' THEN o.name
END as sortName</span>
FROM
  Contact as c
LEFT JOIN Individual as i ON i.id = c.id 
LEFT JOIN Organization as o ON o.id = c.id
<span style="color:green;">ORDER by sortName</span>
</pre>

<p></p>
<p>
This simply adds a switch statement to your field list conditionally setting the value of sortName.
</p>
<p>
There is nothing quite so satisfying as finding the right tool for the right job.  I&#8217;m currently totally in love with the CASE statement, and think everyone should know about it. (hence this bit of evangelism)
</p>
<p>
Tip: don&#8217;t forget that &#8216;,&#8217; after orgName, I keep forgetting it and wondering why my SQL isn&#8217;t working.
</p>
<p>
So concludes today&#8217;s edition of &#8220;Enterprise Development with MySQL&#8221; (&#8220;Kellan Learns SQL&#8221; didn&#8217;t sound as impressive).  In the near future I hope to get a chance to write up some of the PHP libs we&#8217;ve been building/modifying to support object rich web development techniques, completing the picture. (<acronym title="Objects Linux Apache MySQL PHP">OLamp</acronym> anyone?)
</p>
<p>
<h3>Mixing Metaphors</h3>
Single, and Concrete <acronym title="Table Inheritance">TI</acronym> both have their places, and the good news is you can mix these patterns without much difficulty.  Still I&#8217;m happy with both the flexibility and &#8220;OO-ness&#8221; of Concrete Table Inheritance, and once again impressed by the speed, and power of MySQL. (N.B. we&#8217;re targeting 4.1.x, but these above examples all work with 4.0.16 and 4.0.20)
</p></p>
]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2004/08/14/mysql-and-the-case-for-class-table-inheritance/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The CASE statement *is* supported in MySQL 4.0.x series (docs imply MySQL 5.0)</title>
		<link>http://laughingmeme.org/2004/08/12/the-case-statement-is-supported-in-mysql-40x-series-docs-imply-mysql-50/</link>
		<comments>http://laughingmeme.org/2004/08/12/the-case-statement-is-supported-in-mysql-40x-series-docs-imply-mysql-50/#comments</comments>
		<pubDate>Fri, 13 Aug 2004 02:28:27 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[case]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=2458</guid>
		<description><![CDATA[CASE is one of the coolest, most useful SQL constructs ever, more people should use it.]]></description>
			<content:encoded><![CDATA[<p>CASE is one of the coolest, most useful SQL constructs ever, more people should use it.</p>
<p><a href='http://dev.mysql.com/doc/mysql/en/Control_flow_functions.html'>http://dev.mysql.com/doc/mysql/en/Control_flow_functions.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2004/08/12/the-case-statement-is-supported-in-mysql-40x-series-docs-imply-mysql-50/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spatial (R-Tree) Indexes in MySQL 4.1</title>
		<link>http://laughingmeme.org/2004/04/23/spatial-r-tree-indexes-in-mysql-41/</link>
		<comments>http://laughingmeme.org/2004/04/23/spatial-r-tree-indexes-in-mysql-41/#comments</comments>
		<pubDate>Fri, 23 Apr 2004 20:10:13 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[Aside]]></category>
		<category><![CDATA[gis]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=2224</guid>
		<description><![CDATA[I always thought Geo data was a Postgres aberration]]></description>
			<content:encoded><![CDATA[<p>I always thought Geo data was a Postgres aberration</p>
<p><a href='http://jeremy.zawodny.com/blog/archives/000418.html'>http://jeremy.zawodny.com/blog/archives/000418.html</a></p>]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2004/04/23/spatial-r-tree-indexes-in-mysql-41/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PEAR::DB and MySQL&#8217;s AUTO_INCREMENT Fields</title>
		<link>http://laughingmeme.org/2004/01/31/peardb-and-mysqls-auto_increment-fields/</link>
		<comments>http://laughingmeme.org/2004/01/31/peardb-and-mysqls-auto_increment-fields/#comments</comments>
		<pubDate>Sun, 01 Feb 2004 00:23:00 +0000</pubDate>
		<dc:creator>Kellan</dc:creator>
				<category><![CDATA[abstraction]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[pear]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://lm.quxx.info/?p=723</guid>
		<description><![CDATA[In which our protagonist begins a more thorough exploration of PEAR, and quickly runs into a challenge. Non-PHP hackers should feel free to avert their eyes. Maybe this is a well known hack, maybe (hopefully!) there is a better way to do this, but a quick Google search turned up a deafening silence, a marked [...]]]></description>
			<content:encoded><![CDATA[<p>In which our protagonist begins a more thorough exploration of PEAR, and quickly runs into a challenge.  Non-PHP hackers should feel free to avert their eyes.
Maybe this is a well known hack, maybe (hopefully!) there is a better way to do this, but a quick Google search turned up a deafening silence, a marked dearth, of information on how to access a MySQL <code>insert_id</code> (the value created by inserting a row into a table with an <code>AUTO_INCREMENT</code> column).  </p>

<p>I understand that using <code>AUTO_INCREMENT</code> columns is the &#8220;wrong&#8221; way to do things as far as PEAR is concerned, I&#8217;m supposed to use its implemented in PHP sequences, rather then the native and implemented in C method I&#8217;ve been using quite happily for years. (If I find myself migrating my MySQL app to Oracle sometime soon, I promise you <code>AUTO_INCREMENT</code> columns are going to be the least of my worries.)  </p>

<p>Perl DBI faced a similar dilemma <em>many</em> years ago, and decided, wisely, to punt on the whole issue.  They didn&#8217;t provide a solution, and they didn&#8217;t preclude you from using your native solution.  Turns out sometimes doing less is more.  </p>

<p>And lastly, when the hell did PHP get so high and holy that it refuses to let me code the way I want to code?  Stuff like this constantly turns me off of PEAR, the whole thing just kind of has a bad smell about it. </p>

<p>But enough with the ranting, so here is my current, hold-me-over-until-someone-points-out-the-error-of-my-ways solution.</p>

<p>Your PEAR::DB object <code>$dbh</code> holds a reference to the MySQL connection object in <code>$dbh-&gt;connection</code>.  Which allows you take a stroll down memory lane to the bad old days with this little gem: </p>

<pre><code>$id = mysql_insert_id($dbh-&gt;connection)
</code></pre>

<p>For all our veneer of OO civilization, it doesn&#8217;t take much to scratch away the surface and expose our naked barbarian PHP soul does it?</p>
]]></content:encoded>
			<wfw:commentRss>http://laughingmeme.org/2004/01/31/peardb-and-mysqls-auto_increment-fields/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

