<?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>Jason Mooberry &#187; php 5.3</title>
	<atom:link href="http://blog.jasonmooberry.com/tag/php-5-3/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jasonmooberry.com</link>
	<description>Stuff I did for you.</description>
	<lastBuildDate>Sat, 29 Oct 2011 23:41:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.2</generator>
		<item>
		<title>DumbledORM version 0.1 released!</title>
		<link>http://blog.jasonmooberry.com/2010/12/dumbledorm-version-0-1-released/</link>
		<comments>http://blog.jasonmooberry.com/2010/12/dumbledorm-version-0-1-released/#comments</comments>
		<pubDate>Mon, 20 Dec 2010 09:32:22 +0000</pubDate>
		<dc:creator>Jason Mooberry</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dumbledorm]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[novelty orm]]></category>
		<category><![CDATA[php 5.3]]></category>

		<guid isPermaLink="false">http://blog.jasonmooberry.com/?p=204</guid>
		<description><![CDATA[I&#8217;m happy to announce the release of DumbledORM 0.1. It&#8217;s a major revamp from the initial release. It&#8217;s still the same ~200 loc, but now chocked full of comments and under the MIT license. A few noteworthy changes. PDO now throws exceptions by default. The standard default in PDO is to fail silently. This was [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to announce the release of DumbledORM 0.1.  It&#8217;s a major revamp from the initial release.  It&#8217;s still the same ~200 loc, but now chocked full of comments and under the MIT license.</p>
<p>A few noteworthy changes.</p>
<ol>
<li>PDO now throws exceptions by default.  The standard default in PDO is to fail silently.  This was unintended and thanks to <a href="http://twitter.com/#!/jimplush" target="_blank">@jimplush</a> for reporting it.  Be sure to try/catch your code appropriately.</li>
<li><code>Db::execute()</code> method added.  All of the Db methods are publicly accessible and this method is for executing sql that doesn&#8217;t require a fetch (inserts, updates, deletes, etc).  The requirement for this method became clear after turning on exceptions in PDO.</li>
<li>Better docs.  The docs in the README have been updated and reformatted.</li>
</ol>
<p>DumbledORM received a lot of great feedback and attention after it&#8217;s release.  Thank you for all the positive response to this little ORM.  I hope it continues to grow in use and remains small in size.  <img src='http://blog.jasonmooberry.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Download DumbledORM and get started here:<br />
<a href="https://github.com/jasonmoo/DumbledORM">https://github.com/jasonmoo/DumbledORM</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jasonmooberry.com/2010/12/dumbledorm-version-0-1-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MEMP: PHP 5.3 with FPM and nginx via MacPorts</title>
		<link>http://blog.jasonmooberry.com/2010/12/memp-php-5-3-with-fpm-and-nginx-via-macports/</link>
		<comments>http://blog.jasonmooberry.com/2010/12/memp-php-5-3-with-fpm-and-nginx-via-macports/#comments</comments>
		<pubDate>Thu, 02 Dec 2010 01:16:38 +0000</pubDate>
		<dc:creator>Jason Mooberry</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MacPorts]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php 5.3]]></category>
		<category><![CDATA[php-fpm]]></category>

		<guid isPermaLink="false">http://blog.jasonmooberry.com/?p=158</guid>
		<description><![CDATA[I&#8217;ve been considering diving into nginx for a bit now. Rumors of it&#8217;s speed and Cyrillic error messages have intrigued me. With recent forays into node.js apps and their requirement for a free port, I wanted to find a nice solution that complimented the evented speed of node.js without exposing a port publicly for each [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been considering diving into <a href="http://nginx.org/">nginx</a> for a bit now.  Rumors of it&#8217;s speed and Cyrillic error messages have intrigued me.  With recent forays into <a href="http://nodejs.org/">node.js</a> apps and their requirement for a free port, I wanted to find a nice solution that complimented the evented speed of node.js without exposing a port publicly for each app.  As it turns out Nginx is suited quite nicely to this.  But that wasn&#8217;t where it ended.  I found nginx to have a much more interesting and dynamic config language.  And even beyond that it gave me a good excuse to learn more about running PHP as a FastCGI process and how <a href="http://php.net/manual/en/install.fpm.php">PHP-FPM (baked in as of 5.3.3)</a> fits into the picture.  Not sure if MEMP is the correct acronym, but since I&#8217;ve seen talk of <a href="http://library.linode.com/lemp-guides/">LEMP servers</a>, I&#8217;ll run with it.</p>
<p><a href="http://www.macports.org/">MacPorts</a>.  If you&#8217;re not already familiar with it, I recommend reading up before proceeding.</p>
<p>Since I already have MySQL set up and configured I won&#8217;t bother covering it here.  It&#8217;s pretty well documented around the webs.  The main focus here is going to be getting nginx installed and setting up PHP as a service to it with an emphasis on local development.  No need to tweak this for production on my Macbook Pro.</p>
<p>PHP 5.3.3 introduced PHP-FPM (FastCGI Process Manager) to the codebase.  Building it requires a few extra config flags and generates a php-fpm binary.  The binary will manage spawning cgi processes and handling the FastCGI passthru from nginx.  Currently MacPorts does not have an option to build PHP with PHP-FPM.  After some hacking on the current Portfile I arrived at a working solution.  It includes the correct flags, a dependency on libevent, and a startup item.</p>
<p>First things first.</p>
<pre class="brush: bash">
sudo port selfupdate

# recommended but probably not a requirement
sudo port upgrade outdated
sudo port uninstall inactive
</pre>
<p>(If you&#8217;ve already got the php5 package installed, uninstall it and it&#8217;s cohorts to ensure a clean install process going forward.)</p>
<p>This is a bit of a hack and there&#8217;s probably a better way, like submitting a proper patch to MacPorts, but this will get the job done for today.</p>
<pre class="brush: bash">
# replace this file with the Portfile from the gist below
/opt/local/var/macports/sources/rsync.macports.org/release/ports/lang/php5/Portfile
</pre>
<p><a href="https://gist.github.com/724449" target="_blank">https://gist.github.com/724449</a></p>
<p>Then run the regular port install.</p>
<pre class="brush: bash">
sudo port install nginx php5 +fastcgi php5-apc php5-mysql +mysqlnd
</pre>
<p>Next we&#8217;ll need to set up the configs.  There&#8217;s two basic configs that require attention.  First is the nginx config.  Since this is just for a local development env we can be pretty lean on what we need.</p>
<pre class="brush: bash">
# /opt/local/etc/nginx/nginx.conf

worker_processes  1;

error_log  /var/log/nginx/error.log;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile           on;
    keepalive_timeout  65;

    server {
      listen 80;
      server_name   ~^local\.(?<site>.+?)\.com$;
      root  /Users/jason/Sites/$site/web;
      index  index.php index.html;

      location = /favicon.ico {
        log_not_found off;
      }

      location ~ \.php$ {
         fastcgi_pass   unix:/tmp/php-fpm.sock;
         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
         include        fastcgi_params;
      }
    }
}
</pre>
<p>This is the config that I&#8217;m currently using as my generic site config.  It has a few nice features.  First the server name is matched against a regular expression.  So any site that matches <code>local.xxxx.com</code> will be parsed and use the <code>xxxx</code> as a sub-directory in my Sites folder.  This is nice.  So I only need to create a new directory and add my <code>local.xxxx.com</code> domain to <code>/etc/hosts</code> pointed at <code>127.0.0.1</code> and I can immediately begin developing.  Gone are the days of creating a new v-hosts file, enabling it, and restarting apache every time I want to play with a new site&#8217;s code.  The other nicety here is we&#8217;re using a unix socket for the fastcgi passthru.  This is unnoticeably faster on my Mac, but again frees up the need to be concerned with another open port on my system. </p>
<p>It&#8217;s worth noting that any <code>fastcgi_param</code> that you define in this config is available within PHP as a <code>$_SERVER</code> variable. </p>
<p>The second config is the FPM config.  Copy <code>/opt/local/etc/php-fpm.conf.default</code> to <code>/opt/local/etc/php-fpm.conf</code> and open it up. Here are the important ones to modify:</p>
<pre class="brush: plain">
pid = /opt/local/var/run/php-fpm.pid
error_log = /opt/local/var/log/php-fpm.log
listen = /tmp/php-fpm.sock
listen.owner = _www
listen.group = _www
pm.max_children = 1
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 1
pm.max_requests = 500
slowlog = /opt/local/var/log/php-fpm.log.slow
</pre>
<p>It&#8217;s pretty straight-forward.  Lean cus we can. Save and continue.</p>
<p>At this point we&#8217;ve got all the pieces in place.  We just need a way to start/stop/restart nginx and FPM.  I looked for a cleaner way to accomplish this but in the end it came down to a handful of aliases.  Add these to your <code>~/.profile</code>. </p>
<pre class="brush: bash">
# nginx
alias nginx_start='sudo launchctl load /Library/LaunchDaemons/org.macports.nginx.plist'
alias nginx_stop='sudo launchctl unload /Library/LaunchDaemons/org.macports.nginx.plist'
alias nginx_restart='nginx_stop; nginx_start;' 

# php-fpm
alias fpm_start='sudo launchctl load /Library/LaunchDaemons/org.macports.php-fpm.plist'
alias fpm_stop='sudo launchctl unload /Library/LaunchDaemons/org.macports.php-fpm.plist'
alias fpm_restart='fpm_stop; fpm_start'
</pre>
<p>Reopen the Terminal window to enable the new aliases.  Start or restart nginx and FPM as the case may be.</p>
<p>At this point you should be able to create a site directory, add a domain to <code>/etc/hosts</code> and drop in an <code>index.php</code> with <code>phpinfo();</code> to verify that PHP is working.</p>
<p>Hopefully this will be of some use to other aspiring MEMP devs out there.  I found it intensely fun.  <img src='http://blog.jasonmooberry.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jasonmooberry.com/2010/12/memp-php-5-3-with-fpm-and-nginx-via-macports/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Introducing DumbledORM a novelty ORM</title>
		<link>http://blog.jasonmooberry.com/2010/10/introducing-dumbledorm-a-novelty-orm/</link>
		<comments>http://blog.jasonmooberry.com/2010/10/introducing-dumbledorm-a-novelty-orm/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 22:24:23 +0000</pubDate>
		<dc:creator>Jason Mooberry</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dumbledorm]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[novelty orm]]></category>
		<category><![CDATA[php 5.3]]></category>

		<guid isPermaLink="false">http://blog.jasonmooberry.com/?p=128</guid>
		<description><![CDATA[I&#8217;m proud to release DumbledORM today. It is the product of a late night hack sesh with an idea to build a PHP ORM in less than 100 lines. After it&#8217;s all said and done I arrived at 200 lines with lots of features. The decision to call it DumbledORM came after realizing there was [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m proud to release <a href="http://github.com/jasonmoo/DumbledORM">DumbledORM</a> today.  It is the product of a late night hack sesh with an idea to build a PHP ORM in less than 100 lines.  After it&#8217;s all said and done I arrived at 200 lines with lots of features.  The decision to call it DumbledORM came after realizing there was more casting and magic in it than anything out there.  <img src='http://blog.jasonmooberry.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </p>
<p>Some examples of what it can do:</p>
<pre class="brush: php">
// load record with id 13
$user = new User(13);
$user->setName('Jason')->save();

// create new record
$user = new User(array(
  'name' => 'Jason',
  'email' => 'jasonmoo@me.com',
));
$user->save();

// find single record
User::one(array('name' => 'Jason'))->delete();

// apply object methods to entire set at once
PhoneNumber::select('`number` like "607%"')
  ->setLocation('Ithaca, NY')
  ->save();

// relations between objects
$user->create(new PhoneNumber(array(
  'type' => 'home',
  'number' => '607-333-2840',
)))->save();

// update all user phone numbers matching $type
$user->getPhoneNumber('`type` = ?',$type)
  ->setType($new_type)
  ->save();
</pre>
<p>Applying model object methods to entire sets of objects, jQuery style, is made possible by this incantation:</p>
<pre class="brush: php">
final class ResultSet extends ArrayIterator {
  public function __call($method,$params=array()) {
    foreach ($this as $obj) {
      call_user_func_array(array($obj,$method),$params);
    }
    return $this;
  }
}
</pre>
<p>So proud.  I hope you find it fun and maybe even useful.  Although at this point all I can say is that it&#8217;s passing it&#8217;s little tests.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jasonmooberry.com/2010/10/introducing-dumbledorm-a-novelty-orm/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>MongoDB and Symfony.  Yes?  :)  Part 2: Simple Queries</title>
		<link>http://blog.jasonmooberry.com/2009/08/mongodb-and-symfony-yes-part-2-simple-queries/</link>
		<comments>http://blog.jasonmooberry.com/2009/08/mongodb-and-symfony-yes-part-2-simple-queries/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 02:55:46 +0000</pubDate>
		<dc:creator>Jason Mooberry</dc:creator>
				<category><![CDATA[db stuff]]></category>
		<category><![CDATA[doctrine orm]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mysql 5.4]]></category>
		<category><![CDATA[php 5.3]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.jasonmooberry.com/?p=3</guid>
		<description><![CDATA[Ok welcome to the second part of this matchup between MongoDB and MySQL 5.4 via Doctrine ORM on Symfony.  In our previous test MongoDB blew away MySQL's MyISAM and InnoDB engines on raw insert speed.  We were unable to use Doctrine for the inserts test as 2.5 million records quickly runs out of memory in Doctrine.  So we opted for straight sql through PHP 5.3 commands with the MySQL native drivers.  It wasn't even close.

So now let's see how MongoDB holds up against MySQL in the simple query arena.]]></description>
			<content:encoded><![CDATA[<p>Ok welcome to the second part of this matchup between <a href="http://www.mongodb.org/display/DOCS/Home">MongoDB</a> and <a href="http://dev.mysql.com/downloads/mysql/5.4.html">MySQL 5.4</a> via <a href="http://www.doctrine-project.org/">Doctrine ORM</a> on <a href="http://www.symfony-project.org/">Symfony</a>.  In our previous test MongoDB blew away MySQL&#8217;s MyISAM and InnoDB engines on raw insert speed.  We were unable to use Doctrine for the inserts test as 2.5 million records quickly runs out of memory in Doctrine.  So we opted for straight sql through PHP 5.3 commands with the MySQL native drivers.  It wasn&#8217;t even close.</p>
<p>So now let&#8217;s see how MongoDB holds up against MySQL in the simple query arena.</p>
<h3>Simple Queries</h3>
<p>For our purposes here we&#8217;ll only use the fastest setup and we&#8217;ll vary the query parameters for different results. When I set up this test system I actually used a yaml schema so that we could test Doctrine. I had to abandon that in the insert tests, but here it should work fine.</p>
<p><strong>Total Record Count</strong><br />
Mongo:</p>
<pre class="brush: php">
echo $mongo->selectDb('objects')->selectCollection('users')->count();
</pre>
<p>The response time was 25ms (only 1ms over Symfony&#8217;s overhead).</p>
<p>MyISAM with Doctrine ORM:</p>
<pre class="brush: php">
echo Doctrine_Query::create()->from('User u')->count();
</pre>
<p>The response time was 30ms (only 5ms over Symfony&#8217;s overhead).</p>
<p>InnoDB with Doctrine ORM:</p>
<pre class="brush: php">
echo Doctrine_Query::create()->from('User u')->count();
</pre>
<p>The response time was 916ms..</p>
<p><strong>Unindexed query</strong></p>
<p>Mongo:</p>
<pre class="brush: php">
$query = array(
  'pet' => 'sugar glider',
);
echo $users->find($query)->count();
</pre>
<p>This returns a count of 500k and after several tests the average response time was 950ms.</p>
<p>MyISAM with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.pet = "sugar glider"');
echo $users->count();
</pre>
<p>This returns a count of 500k and after several tests the average response time was 870ms.</p>
<p>InnoDB with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.pet = "sugar glider"');
echo $users->count();
</pre>
<p>This returns a count of 500k and after several tests the average response time was 1300ms.</p>
<p><strong>Indexed query</strong><br />
Mongo:</p>
<pre class="brush: php">
$query = array(
  'number' => 1005,
);
echo $users->find($query)->count();
</pre>
<p>This returns a count of 250 in 25ms.</p>
<p>MyISAM with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber = 1005');
echo $users->count();
</pre>
<p>This returns a count of 250 in 30ms.</p>
<p>InnoDB with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber = 1005');
echo $users->count();
</pre>
<p>This returns a count of 250 in 30ms.</p>
<p><strong>Indexed range query</strong><br />
Mongo:</p>
<pre class="brush: php">
$query = array(
  'number' => array('$gt'=>1000,'$lt'=>1005),
);
echo $users->find($query)->count();
</pre>
<p>This returns a count of 1,000 in 26ms.</p>
<p>MyISAM with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber between 1001 and 1004');
echo $users->count();
</pre>
<p>This returns a count of 1,000 in 32ms.</p>
<p>InnoDB with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber between 1001 and 1004');
echo $users->count();
</pre>
<p>This returns a count of 1,000 in 31ms.</p>
<p><strong>Indexed range query (large set)</strong><br />
Mongo:</p>
<pre class="brush: php">
$query = array(
  'number' => array('$gt'=>1000,'$lt'=>9005),
);
echo $users->find($query)->count();
</pre>
<p>This returns a count of 2,001,000 in 2.5 seconds.</p>
<p>MyISAM with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber between 1001 and 9004');
echo $users->count();
</pre>
<p>This returns a count of 2,001,000 in 1.5 seconds.</p>
<p>InnoDB with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber between 1001 and 9004');
echo $users->count();
</pre>
<p>This returns a count of 2,001,000 in 760ms.</p>
<p><strong>Indexed range query, ordered, limit 10, with output</strong><br />
Mongo:</p>
<pre class="brush: php">
$query = array(
  'number' => array('$gt'=>1000,'$lt'=>9005),
);
$sort = array(
  'number' => -1,
);
foreach ($users->find($query)->sort($sort)->limit(10) as $user)
{
  echo $user['_id'],':',$user['number'],'
';
}
</pre>
<p>This returns in 26ms.</p>
<p>MyISAM with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber between 1001 and 9004')
   ->orderBy('u.onumber desc')
   ->limit(10);
foreach ($users->execute() as $user)
{
  echo $user->getId(),':',$user->getOnumber(),'
';
}
</pre>
<p>This returns in 35ms.</p>
<p>InnoDB with Doctrine ORM:</p>
<pre class="brush: php">
$users = Doctrine_Query::create()
   ->from('User u')
   ->where('u.onumber between 1001 and 9004')
   ->orderBy('u.onumber desc')
   ->limit(10);
foreach ($users->execute() as $user)
{
  echo $user->getId(),':',$user->getOnumber(),'
';
}
</pre>
<p>This returns in 34ms.</p>
<table border="0">
<tbody>
<tr>
<th>Query</th>
<th>MongoDB</th>
<th>MyISAM</th>
<th>InnoDB</th>
</tr>
<tr>
<td>Total Record Count</td>
<td><span style="color:#339966;"><strong>25ms</strong></span></td>
<td><span style="color:#33cccc;">30ms</span></td>
<td><span style="color:#3366ff;">916ms</span></td>
</tr>
<tr>
<td>Unindexed query</td>
<td><span style="color:#339966;">950ms</span></td>
<td><span style="color:#33cccc;"><strong>870ms</strong></span></td>
<td><span style="color:#3366ff;">1300ms</span></td>
</tr>
<tr>
<td>Indexed query</td>
<td><span style="color:#339966;"><strong>25ms</strong></span></td>
<td><span style="color:#33cccc;">30ms</span></td>
<td><span style="color:#3366ff;">30ms</span></td>
</tr>
<tr>
<td>Indexed range query</td>
<td><span style="color:#339966;"><strong>26ms</strong></span></td>
<td><span style="color:#33cccc;">32ms</span></td>
<td><span style="color:#3366ff;">31ms</span></td>
</tr>
<tr>
<td>Indexed range query (large set)</td>
<td><span style="color:#339966;">2.5s</span></td>
<td><span style="color:#33cccc;">1.5s</span></td>
<td><span style="color:#3366ff;"><strong>760ms</strong></span></td>
</tr>
<tr>
<td>Indexed range query, ordered, limit 10, with output</td>
<td><span style="color:#339966;"><strong>26ms</strong></span></td>
<td><span style="color:#33cccc;">35ms</span></td>
<td><span style="color:#3366ff;">34ms</span></td>
</tr>
</tbody>
</table>
<p>Well we&#8217;ve got a lot of interesting numbers here.  Seems as though MongoDB has a little trouble with large set range searches, and unindexed queries, but kicks butt in the other tests.  And InnoDB seems to handle the large ranged queries the best with a modest showing in the rest, except for total record count..  Wth happened there?  And MyISAM seems to be a pretty speedy running mate for everything, with an edge on the unindexed queries.</p>
<p>Real world value of these tests?  I would have liked to run even more extensive queries here, but wanted to make sure I saved time for the next section which covers relations.  But a decent real world example would be that last test.  And MongoDB seems to have almost a 10ms edge on MySQL when it comes to this.</p>
<p>I realize that these results are not accounting for the overhead of using Doctrine.  And I&#8217;m ok with that because I&#8217;m interested in real development environment stuff, not so much what is the bare bones potential.  And so far MongoDB is doing well, although, the features of Doctrine would largely be missing from a MongoDB setup until we get a good framework that can sit on top of a MongoDB (which might even out the scores in many of these queries).</p>
<p>In the next section we&#8217;ll try to see how we can use MongoDB to persist relations between objects using their MongoDBRef class and a little forethought..  <img src='http://blog.jasonmooberry.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>System Setup</strong><br />
Some VPS setup with 1and1.com with a gig of dedicated ram<br />
Ubuntu 8.04.1 64bit Hardy<br />
Symfony 1.2.9 dev updated repository<br />
MongoDB Linux 64 0.9.9 (mongodb-linux-x86_64-0.9.9.tgz)<br />
Doctrine 1.0.10 (bundled with Symfony)<br />
Apache 2.2.8<br />
PHP 5.3.0 with mysqlnd<br />
MySQL 5.4 with the my.cnf for medium systems<br />
PECL MongoDB package 0.9.4</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jasonmooberry.com/2009/08/mongodb-and-symfony-yes-part-2-simple-queries/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>MongoDB and Symfony.  Yes?  :)  Part 1: Inserts</title>
		<link>http://blog.jasonmooberry.com/2009/08/mongodb-and-symfony-yes-part-1-inserts/</link>
		<comments>http://blog.jasonmooberry.com/2009/08/mongodb-and-symfony-yes-part-1-inserts/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 02:55:26 +0000</pubDate>
		<dc:creator>Jason Mooberry</dc:creator>
				<category><![CDATA[db stuff]]></category>
		<category><![CDATA[doctrine orm]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mysql 5.4]]></category>
		<category><![CDATA[php 5.3]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.jasonmooberry.com/?p=13</guid>
		<description><![CDATA[MongoDB caught my eye recently as a potential solution to managing large data sets with dynamically generated relations.  But I didn't know what to expect since I had not played around with any of the other DODBs.  So I started setting up test cases and decided to share them with you.]]></description>
			<content:encoded><![CDATA[<h2><a href="http://www.mongodb.org/display/DOCS/Home">MongoDB</a></h2>
<p>What is it? That was my first thought. A quick review of their site gave me a taste of something that sounded good. I&#8217;ve been working with <a href="http://www.symfony-project.org/">Symfony</a> and <a href="http://www.doctrine-project.org/">Doctrine</a> for almost a year now and really loving it.  Started writing a custom orm for my <a href="http://www.otc-productions.com">current employer</a> and found that it really brought to light some issues with relational modeling. For instance, free-form relations between objects. In a <a href="http://en.wikipedia.org/wiki/Relational_model">RDBMS</a> you&#8217;ve got to setup your long table with key/val pairs that reference other tables and ids and then there&#8217;s the whole issue of efficiently joining on that. I found that trying to translate that structure into an orm style development tool was challenging to say the least. I wondered if a <a href="http://en.wikipedia.org/wiki/Document-oriented_database">DODB</a> would offer a better way. Ideally the speed of development AND the speed of the data manipulation would increase. MongoDB has a nice little DBRef class that allows you to reference your way around your collections, effectively hardcoding your joins at the data level. Would it be a nice way to handle creating relationships between objects without premeditation?</p>
<h3>Setup</h3>
<p>Ok so I wanted to set up some simple benchmarks just to see what we were looking at as far as ease of use and speed for basic dumb things. I setup a basic Symfony/Doctrine project and pulled down the latest version of MongoDB for Linux 64.</p>
<p>I started my mongod server without the web interface since I won&#8217;t need it for this:</p>
<pre class="brush: shell">mongod --dbpath=/var/www/sites/mongobjects/web/data/mongodb/ --nohttpinterface --quiet &amp;
Sun Aug 23 04:09:56 Mongo DB : starting : pid = 11534 port = 27017 dbpath = /var/www/sites/mongobjects/web/data/mongodb/ master = 0 slave = 0  64-bit
Sun Aug 23 04:09:56 db version v0.9.9, pdfile version 4.4
Sun Aug 23 04:09:56 git version: cd0bf23e74ef8ded0684f74996ee762889b93294
Sun Aug 23 04:09:56 sys info: Linux ofc-n1.10gen.com 2.6.23.17-88.fc7 #1 SMP Thu May 15 00:02:29 EDT 2008 x86_64
Sun Aug 23 04:09:56 waiting for connections on port 27017</pre>
<p>And we&#8217;re up and running.</p>
<h3><strong>Filling our Databases</strong></h3>
<p>These tests will be run via a page load in Symfony. So all the code takes place within an actions class method that is triggered by a url and tracked via symfony&#8217;s developer bar. A simple benchmarking tool that produces a little fluctuation in the numbers, but fine for what we&#8217;re doing here.  It&#8217;s worth noting that on this system Symfony takes ~24ms to render a page without anything else happening.  So all our tests will have an extra ~24ms from Symfony execution time.</p>
<p><strong>Mongo<br />
</strong></p>
<p>I wanted a simple single table test setup so I decided to build a user set of 500,000 users. But then I realized toward the end of this article that I my 5 types of pets actually made all my tests insert 2.5 million records.  So that&#8217;s what we&#8217;re using.  Loading data with MongoDB was simple and quick. Just select the db and collection you want and if it&#8217;s not already in existence it will be when you start writing to it.</p>
<pre class="brush: php">$mongo = new Mongo;
$users = $mongo-&gt;selectDb('objects')-&gt;selectCollection('users');
$animals = array('cat','dog','sugar glider','pigeon','dove');

for ($j=0; $j &lt; 50; $j++)
{
  for ($i=0; $i &lt; 10000; $i++)
  {
    foreach ($animals as $animal)
    {
      $users-&gt;save(array(
        'number' =&gt; $i,
        'pet' =&gt; $animal,
        'name' =&gt; 'Jason Mooberry',
        'email' =&gt; 'jason@barkingsnake.com',
      ));
    }
  }
}</pre>
<p>Mongo ran through this like it was bored.  Occasionally it had to create a new datafile but this was only apparent in the log.</p>
<pre class="brush: shell">Sun Aug 23 04:23:22 newExtent: objects.users file 0 full, adding a new file
Sun Aug 23 04:23:22 allocating new datafile /var/www/sites/mongobjects/web/data/mongodb/objects.1, filling with zeroes...
Sun Aug 23 04:23:22 done allocating datafile /var/www/sites/mongobjects/web/data/mongodb/objects.1, size: 134217728, took 0.243 secs</pre>
<p>MongoDB uses preallocated data files to store it BSON data. Data files are created in increasingly larger sizes to handle fragmentation more efficiently.</p>
<p>The total insert time on 2.5 million records was <span style="color:#339966;"><strong>55 seconds</strong></span>.  Let&#8217;s see how MySQL holds up.</p>
<p><strong>MySQL</strong></p>
<p>OK let&#8217;s see what happens when we create a simple table in MySQL and load the same 2.5 million user set. I created a simple table in Navicat:</p>
<pre class="brush: sql">CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`onumber` int(11) DEFAULT NULL,
`pet` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8</pre>
<p>I chose InnoDB since <a href="http://dev.mysql.com/tech-resources/articles/mysql-54.html">MySQL 5.4 is boasting some big improvements in the InnoDB engine</a>.  I realize much of that is about large scale systems with complex joins, but let&#8217;s just see how it does.  <img src='http://blog.jasonmooberry.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Running an insert set of this size is an impossibility with this version of Doctrine. It quickly runs out of memory. I think this might be solved by a better garbage collection method in Doctrine 2.0 or perhaps even 1.1, but not in 1.0. So we do it the old fashioned way:</p>
<pre class="brush: php">$db = mysql_connect('localhost', 'mongobjects_user', 'm0ng0');
mysql_select_db('mongobjects',$db);
$animals = array('cat','dog','sugar glider','pigeon','dove');
for ($j=0; $j &lt; 50; $j++)
{
  for ($i=0; $i &lt; 10000; $i++)
  {
    foreach ($animals as $animal)
    {
      $qs = "insert into `user` (`onumber`,`pet`,`name`,`email`) values ($i,'$animal','Jason Mooberry','jason@barkingsnake.com')";
      mysql_query($qs);
    }
  }
}</pre>
<p>OK so I hit the url and wait&#8230; tick tock.. tick tock.. TICK TOCKKKKK&#8230; After several minutes I peek at the insert log and see that MySQL is still diligently inserting rows. So I continue to wait and wonder what my max execution time is set at..</p>
<p>After having a conversation with my girlfriend about stuff, <em>MySQL finally crosses the finish line in <span style="color:#ff0000;"><strong>18.23 minutes</strong></span></em>&#8230; I realize I have the query log on and that is a bit of a hog, so let&#8217;s rerun it with the log turned off. bin-log appears to be on as well and since we&#8217;re not replicating here, I&#8217;ll turn that off too.</p>
<p>I restart MySQL, truncate the table, and try again.</p>
<p>While I wait I&#8217;d like to pontificate on the merits of a fast file system. ReiserFS is the default system on my vps but my recent experiences with XFS have led me to believe it to be a better option&#8230;  <span style="color:#808080;">[10 mins go by]</span> &#8230; and so that is why I think Hans Reiser is a jerk!  OH um I think we&#8217;ve finished.</p>
<p><em>MySQL without the logs comes in at <span style="color:#ff6600;"><strong>9.96 minutes</strong></span></em> for inserting 2.5 million records. That&#8217;s a big difference. Maybe it&#8217;s worth checking the speed with MyISAM. I change the table to MyISAM, truncate and repeat.</p>
<p><em>Ok MyISAM puts MySQL back in the running with an insert of 2.5 million records in<span style="color:#33cccc;"><strong> 2.58 minutes</strong></span></em>.  I guess it&#8217;s probably a better comparison with MyISAM since MongoDB isn&#8217;t transactional and we&#8217;re not dealing with foreign key constraints.  Still I was hoping for a much stronger showing from InnoDB..</p>
<p>EDIT: After rummaging through this article today about <a href="http://www.doctrine-project.org/blog/transactions-and-performance">auto-commit transaction handling in InnoDB and PHP</a>, I decided to give InnoDB another chance to prove it&#8217;s worth here.  So I reran the insert tests inside a single transaction:</p>
<pre class="brush: php">$animals = array('cat','dog','sugar glider','pigeon','dove');
$db = mysql_connect('localhost', 'mongobjects_user', 'm0ng0');
mysql_select_db('mongobjects',$db);
mysql_query('START TRANSACTION',$db);
for ($j=0; $j &lt; 50; $j++)
{
  for ($i=0; $i &lt; 10000; $i++)
  {
    foreach ($animals as $animal)
    {
      $qs = "insert into `user` (`onumber`,`pet`,`name`,`email`) values ($i,'$animal','Jason Mooberry','jason@barkingsnake.com')";
      mysql_query($qs,$db);
    }
  }
}
mysql_query('COMMIT',$db);</pre>
<p>And InnoDB is back in this thing&#8230; sort of.  2.5 million rows inserted inside a single transaction: <span style="color:#3366ff;"><strong>2.45 minutes.</strong></span> I also reran this with the Index specified below and it ran in <span style="color:#3366ff;"><strong>3.28 minutes</strong></span>.  Our use case may not actually involve this type of scenario so it&#8217;s of mixed value.</p>
<h3>Indexes</h3>
<p>Our insert tests were run without an index to slow it down.  The inserted records were done in 50 batches of 10,000 batches of 5 records with a number field storing the record number within it&#8217;s batch.  The end result is that the number field will match in 250 records for each number.  So a nice ranged query on that column will be a good way to test our search speed.  So lets add an index to our number column and rerun our inserts.</p>
<p><strong>Mongo</strong></p>
<p>Adding an index to a collection in MongoDB consists of a php command:</p>
<pre class="brush: php">$mongo = new Mongo;
$users = $mongo-&gt;selectDb('objects')-&gt;selectCollection('users')-&gt;ensureIndex(array('number'=&gt;1));</pre>
<p>Seeting the key &#8216;number&#8217; to 1 creates an ascending index.</p>
<p>I&#8217;ve gone ahead and rm&#8217;d all the mongo db files so that we get an accurate test.</p>
<pre class="brush: php">$mongo = new Mongo;
$users = $mongo-&gt;selectDb('objects')-&gt;selectCollection('users');
$users-&gt;ensureIndex(array('number'=&gt;1));
$animals = array('cat','dog','sugar glider','pigeon','dove');
<pre>for ($j=0; $j &lt; 50; $j++)
{
  for ($i=0; $i &lt; 10000; $i++)
  {
    foreach ($animals as $animal)
    {
      $users-&gt;save(array(
        'number' =&gt; $i,
        'pet' =&gt; $animal,
        'name' =&gt; 'Jason Mooberry',
        'email' =&gt; 'jason@barkingsnake.com',
      ));
    }
  }
}</pre>
</pre>
<p>With the index on the number column Mongo inserts 2.5 million records in<em><strong><span style="color:#339966;"> 1.32 minutes</span></strong></em>.  Not bad I guess.  Let&#8217;s see how MySQL does.</p>
<p><strong>MySQL (MyISAM)</strong></p>
<p>I&#8217;m sticking with MyISAM for the rest of these tests since I don&#8217;t care to wait all day for my tests to run and the feature sets match a little better between MongoDB and MyISAM.  So I&#8217;m just gonna truncate the table and add an index and rerun.</p>
<pre class="brush: sql">CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
 `onumber` int(11) DEFAULT NULL,
 `pet` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
 `email` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `user_number_idx` (`onumber`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8</pre>
<p><em>PHP did not change for this test.</em></p>
<p>MySQL handles the insert with roughly the same increase at <span style="color:#33cccc;"><em><strong>3.02 minutes</strong></em></span>.</p>
<h3>Insert Test Breakdown</h3>
<p>Here&#8217;s the breakdown for our insert tests with the various flavors of MySQL and MongoDB.  It&#8217;s a pretty impressive difference on massive inserts.</p>
<table border="0">
<tbody>
<tr>
<th>Type</th>
<th>Time</th>
</tr>
<tr>
<td>MongoDb without index</td>
<td><span style="color:#339966;"><strong>55 seconds</strong></span></td>
</tr>
<tr>
<td>MongoDB with single index</td>
<td><span style="color:#339966;"><strong>1.32 minutes</strong></span></td>
</tr>
<tr>
<td>MySQL InnoDB with logging</td>
<td><span style="color:#ff0000;">18.23 minutes</span></td>
</tr>
<tr>
<td>MySQL InnoDB</td>
<td><span style="color:#ff6600;">9.96 minutes</span></td>
</tr>
<tr>
<td>MySQL InnoDB single transaction</td>
<td><span style="color:#3366ff;">2.45 minutes</span></td>
</tr>
<tr>
<td>MySQL InnoDB single transaction, with single index</td>
<td><span style="color:#3366ff;">3.28 minutes</span></td>
</tr>
<tr>
<td>MySQL MyISAM without index</td>
<td><span style="color:#33cccc;">2.58 minutes</span></td>
</tr>
<tr>
<td>MySQL MyISAM with single index</td>
<td><span style="color:#33cccc;">3.02 minutes</span></td>
</tr>
</tbody>
</table>
<p>The winner is clear here on inserts.  But let&#8217;s see how MongoDB holds up with Simple Queries, and Relations&#8230;</p>
<div style="font-size:12px;"><strong>System Setup</strong></p>
<ul>
<li>Some VPS setup with 1and1.com with a gig of dedicated ram</li>
<li>Ubuntu 8.04.1 64bit Hardy</li>
<li>Symfony 1.2.9 dev updated repository</li>
<li>MongoDB Linux 64 0.9.9 (mongodb-linux-x86_64-0.9.9.tgz)</li>
<li>Doctrine 1.0.10 (bundled with Symfony)</li>
<li>Apache 2.2.8</li>
<li>PHP 5.3.0 with mysqlnd</li>
<li>MySQL 5.4 with the my.cnf for medium systems</li>
<li>PECL MongoDB package 0.9.4</li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.jasonmooberry.com/2009/08/mongodb-and-symfony-yes-part-1-inserts/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.161 seconds -->

