<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>railsexpress.de</title>
    <link>http://railsexpress.de/blog</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    
      <item>
        <title>blog maintenance</title>
        <description>&lt;p&gt;It&amp;#8217;s time for an OS upgrade. I&amp;#8217;m going to reinstall the server over Easter. Will be back next week.&lt;/p&gt;</description>
        <pubDate>2009-04-09T10:44:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2009/04/09/blog-maintenance</guid>
        <link>/blog/articles/2009/04/09/blog-maintenance</link>
      </item>
    
      <item>
        <title>Goodbye Trac</title>
        <description>&lt;p&gt;I moved my ticketing system to &lt;a href=&quot;http://railsexpress.lighthouseapp.com/&quot;&gt;lighthouse&lt;/a&gt;. It just doesn&amp;#8217;t make sense anymore to maintain my own system on this server.&lt;/p&gt;</description>
        <pubDate>2009-03-14T06:27:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2009/03/14/goodbye-trac</guid>
        <link>/blog/articles/2009/03/14/goodbye-trac</link>
      </item>
    
      <item>
        <title>Ditching Subversion</title>
        <description>&lt;p&gt;I&amp;#8217;ve converted all my public &lt;a href=&quot;http://railsexpress.de/plugins/trac&quot;&gt;subversion repositories&lt;/a&gt; to git. They&amp;#8217;re now hosted on &lt;a href=&quot;http://github.com/skaes&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There were several reasons for doing so:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;After having used git for some time now, subversion really feels awkward to use, even though no branching and merging was required so far.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;It should now be much easier for users to maintain their own extensions of the plugins.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;I will need to reinstall my server in the near future. I was not looking forward to reinstall subversion and make proper backups of all the repositories. Having the code in git, I don&amp;#8217;t need to make server backups of the repositories anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the server gets reinstalled, the subversion support will be dropped completely.&lt;/p&gt;</description>
        <pubDate>2009-03-13T16:35:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2009/03/13/ditching-subversion</guid>
        <link>/blog/articles/2009/03/13/ditching-subversion</link>
      </item>
    
      <item>
        <title>railsbench edge version available from github</title>
        <description>&lt;p&gt;A while ago I moved my railsbench source repository to github. One of the benefits I hoped for was the possibility to have prerelease versions of the railsbench gem available for other people to try out, with minimal effort on my side. But github didn&amp;#8217;t manage to build my gem automatically, as promised. I followed all instructions to the letter, but it just didn&amp;#8217;t build. But recently the github gem builder received an update and now it does seem to work.&lt;/p&gt;
&lt;p&gt;From now on you can install the bleeding edge version of railsbench from github. Do&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
gem sources -a http://gems.github.com
&lt;/pre&gt;
&lt;p&gt;to add github as a remote gem repository and then do&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
sudo gem install skaes-railsbench
&lt;/pre&gt;
&lt;p&gt;There a lots of changes in the upcoming release, as I haven&amp;#8217;t released a new version for a long time. They are summarized in &lt;a href=&quot;http://github.com/skaes/railsbench/blob/15050d8572320fa8552eb5309cb586b2db023347/latest_changes.txt&quot;&gt;latest_changes.txt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Stefan&lt;/p&gt;</description>
        <pubDate>2009-02-16T13:20:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2009/02/16/railsbench-edge-version-available-from-github</guid>
        <link>/blog/articles/2009/02/16/railsbench-edge-version-available-from-github</link>
      </item>
    
      <item>
        <title>How to open textmate links in Emacs on OS X</title>
        <description>&lt;p&gt;I must admit that I&amp;#8217;ve had some jealous feelings lately, watching developers using texmate. It wasn&amp;#8217;t the editor which impressed me, of course, but the support they get out of using the &lt;a href=&quot;http://github.com/drnic/rails-footnotes/tree/master&quot;&gt;footnotes plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, as a dedicated member of the &lt;a href=&quot;http://www.youtube.com/watch?v=qIF5xnkcncI&quot;&gt;church of emacs&lt;/a&gt;, I muttered to myself: &amp;#8220;dammit, it must be possible to invoke the &lt;a href=&quot;http://www.dina.kvl.dk/~abraham/religion/&quot;&gt;one true editor&lt;/a&gt; instead&amp;#8221;, even on a Mac.&lt;/p&gt;
&lt;p&gt;And indeed, it&amp;#8217;s possible. Here&amp;#8217;s how to do it.&lt;/p&gt;
&lt;p&gt;First, open the the Info.plist file of the Emacs you installed (for me it&amp;#8217;s in /Applications/MacPorts/Emacs.app/Contents/Info.plist). Find the lines which look like&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLSchemes&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;mailto&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and add txmt urls:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLSchemes&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;mailto&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;txmt&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Second, download &lt;a href=&quot;/downloads/textmate-links.el&quot;&gt;textmate-links.el&lt;/a&gt;, install it into your Emacs load path and add (require &amp;#8217;textmate-links) to your init.el.&lt;/p&gt;
&lt;p&gt;Third, get &lt;a href=&quot;http://www.rubicode.com/Software/RCDefaultApp/&quot;&gt;RcDefaultApp&lt;/a&gt; if you haven&amp;#8217;t installed it already. This will allow you to associate txmt: urls with Emacs. Open it and select the Applications tab. Navigate to Emacs and &lt;a href=&quot;/blog/files/emacs/rcdefaultapps-step1.png&quot;&gt;check the txtmt checkbox&lt;/a&gt; and select it as the default appplication for txmt urls.&lt;/p&gt;
&lt;p&gt;Then navigate to the Urls tab and &lt;a href=&quot;/blog/files/emacs/rcdefaultapps-step2.png&quot;&gt;select Emacs as the handler for txmt urls&lt;/a&gt;, if this hasn&amp;#8217;t happened automatically already.&lt;/p&gt;
&lt;p&gt;Next time you click on a txmt: link in the browser of your choice, it should open the file in Emacs.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;</description>
        <pubDate>2009-01-23T21:08:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2009/01/23/how-to-open-textmate-links-in-emacs-on-os-x</guid>
        <link>/blog/articles/2009/01/23/how-to-open-textmate-links-in-emacs-on-os-x</link>
      </item>
    
      <item>
        <title>Ruby/Rails Consultants wanted</title>
        <description>&lt;p&gt;I need 2 additional consultants for the Rails &lt;span class=&quot;caps&quot;&gt;CRM&lt;/span&gt; project I&amp;#8217;m managing for &lt;a href=&quot;http://www.autoscout24.de&quot;&gt;Autoscout24&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a &lt;i&gt;massive&lt;/i&gt; Rails application with 198 models and 60 controllers. A large part of the code base consists of business logic.&lt;/p&gt;
&lt;p&gt;Requirements:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;brightness&lt;/li&gt;
	&lt;li&gt;ability to get things done&lt;/li&gt;
	&lt;li&gt;willingness to dive into an existing code base, fix stuff and extend existing functionality&lt;/li&gt;
	&lt;li&gt;good social skills&lt;/li&gt;
	&lt;li&gt;ability to speak English (German is a plus)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re interested, send me your credentials.&lt;/p&gt;
&lt;p&gt;The contract duration would be 6 months initially.&lt;/p&gt;
&lt;p&gt;This is an &lt;i&gt;on site&lt;/i&gt; project in Munich, telecommuting is unfortunately not possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; the positions have been filled.&lt;/p&gt;</description>
        <pubDate>2008-01-23T16:45:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2008/01/23/ruby-rails-consultants-wanted</guid>
        <link>/blog/articles/2008/01/23/ruby-rails-consultants-wanted</link>
      </item>
    
      <item>
        <title>Writing Efficient Ruby Code - Short Cut</title>
        <description>&lt;p&gt;This has been a busy year for me, but I have finally managed to complete the first chapter of my book &amp;#8220;Performance Rails&amp;#8221; and Addison Wesley has published it as a &lt;a href=&quot;http://www.informit.com/store/product.aspx?isbn=0321540034&amp;amp;rl=1&quot;&gt;digital short cut&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a collection of performance patterns (and anti patterns) which I have successfully applied to speed up the Rails framework. I hope you will find it useful.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: here some comments by readers of the short cut:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://mandarinsoda.com/2007/11/26/ruby-performance-best-practices/&quot;&gt;Mandarin Soda&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.h3rald.com/articles/efficient-ruby-code-shortcut-review/&quot;&gt;H3rald&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
        <pubDate>2007-12-28T19:10:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2007/12/28/writing-efficient-ruby-code-short-cut</guid>
        <link>/blog/articles/2007/12/28/writing-efficient-ruby-code-short-cut</link>
      </item>
    
      <item>
        <title>Rails Edge Performance</title>
        <description>&lt;p&gt;Listening to David's RailsConf Europe 2007 keynote, I've learned that he's going to a release a beta version soonish. He's asked me to do some benchmarking, comparing the performance of edge Rails to the latest stable branches. Here's a chart:&lt;/p&gt;


&lt;div style=&quot;margin:15px;&quot;&gt;
&lt;a href=&quot;/blog/files/charts/stable_11_stable_12_edge.png&quot; target=_blank&gt;&lt;img src=&quot;/blog/files/charts/stable_11_stable_12_edge_small.png&quot;&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;font size=-1&gt;stable11 is the current svn version of branch 1-1-stable, stable12 is current version of 1-2-stable branch and edge is the current version of Rails trunk. Numbers are requests per second (measured on my MacBook during David's talk).&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;If you're a numbers type, these are the numbers:&lt;/p&gt;

&lt;style type=&quot;text/css&quot;&gt;
&lt;!--
.perf_header, .perf_data, .perf_name { font-size:80%; padding-left:5px; padding-right:5px; }
.perf_header { text-align:center; vertical-align:top; font-weight:bold;}
.i { font-style:italic; }
.b { font-weight:bold; }
.c1 { background:#fff3df; }
.c2 { background:#dfedff; }
.factor { background:#efe0ef; }
.factor_red_alert { background:#CC303B; }
.factor_red { background:#FF6060; }
.factor_reddish { background:#FFA766; }
.factor_green_alert { background:#0B8900; }
.factor_green { background:#6AB788; }
.factor_greenish { background:#7FFFB0; }
.name { background:#dfdfdf; }
.perf_name   { text-align:left;   }
.perf_data   { text-align:right;  }
--&gt;
&lt;/style&gt;
&lt;div style=&quot;margin:15px;&quot;&gt;
&lt;table cellspacing=1px&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;empty                             &lt;/td&gt;
&lt;td class='perf_data c1'&gt;0.94709&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.05049&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1055.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;951.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;0.95&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.05&lt;/td&gt;
&lt;td class='perf_data factor_red'&gt;0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;welcome                           &lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.22878&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.34536&lt;/td&gt;
&lt;td class='perf_data c1'&gt;813.8&lt;/td&gt;&lt;td class='perf_data c2'&gt;743.3&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.23&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.35&lt;/td&gt;
&lt;td class='perf_data factor_reddish'&gt;0.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;recipes                           &lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.37214&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.50364&lt;/td&gt;
&lt;td class='perf_data c1'&gt;728.8&lt;/td&gt;&lt;td class='perf_data c2'&gt;665.1&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.37&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.50&lt;/td&gt;
&lt;td class='perf_data factor_reddish'&gt;0.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;my_recipes                        &lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.36958&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.49912&lt;/td&gt;
&lt;td class='perf_data c1'&gt;730.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;667.1&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.37&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.50&lt;/td&gt;
&lt;td class='perf_data factor_reddish'&gt;0.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;show                              &lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.46944&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.27918&lt;/td&gt;
&lt;td class='perf_data c1'&gt;288.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;233.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.47&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.28&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;cat                               &lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.72675&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.58788&lt;/td&gt;
&lt;td class='perf_data c1'&gt;268.3&lt;/td&gt;&lt;td class='perf_data c2'&gt;218.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.73&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.59&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;cat_page5                         &lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.85624&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.68700&lt;/td&gt;
&lt;td class='perf_data c1'&gt;259.3&lt;/td&gt;&lt;td class='perf_data c2'&gt;213.4&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.86&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.69&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;letter                            &lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.69970&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.54140&lt;/td&gt;
&lt;td class='perf_data c1'&gt;270.3&lt;/td&gt;&lt;td class='perf_data c2'&gt;220.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.70&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.54&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name i'&gt;all requests                     &lt;/td&gt;
&lt;td class='perf_data c1'&gt;19.66971&lt;/td&gt;&lt;td class='perf_data c2'&gt;23.49406&lt;/td&gt;
&lt;td class='perf_data c1'&gt;406.7&lt;/td&gt;&lt;td class='perf_data c2'&gt;340.5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.46&lt;/td&gt;&lt;td class='perf_data c2'&gt;2.94&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;/tr&gt;&lt;tr&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left'&gt;GC statistics&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 #gc&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 #gc&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 gc%&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 #gc%&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;                                  &lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.27657&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.09640&lt;/td&gt;
&lt;td class='perf_data c1'&gt;21.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;25.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;11.57&lt;/td&gt;&lt;td class='perf_data c2'&gt;13.18&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.74&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p style=&quot;font-size:80%;&quot;&gt;c1: 1.2-stable, c2: edge, r/s: requests per second, ms/r: milliseconds per request&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I haven't had time to analyze the code, but it seems that anything loading a large number of active record objects takes a rather large performance hit.&lt;/p&gt;

&lt;p&gt;I hope we can improve performance before 2.0 gets finally released. Unfortunately, I have almost no time to work on this. However, if anyone has a performance patch, I can look into the it.&lt;/p&gt;


</description>
        <pubDate>2007-09-18T11:53:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2007/09/18/rails-edge-performance</guid>
        <link>/blog/articles/2007/09/18/rails-edge-performance</link>
      </item>
    
      <item>
        <title>Rails Consultant wanted</title>
        <description>&lt;p&gt;I&amp;#8217;m looking for an experienced Rails consultant to complement the team working for Autoscout24 on the International Sales Synergy Project which I am managing.&lt;/p&gt;
&lt;p&gt;Requirements:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;brightness&lt;/li&gt;
	&lt;li&gt;ability to get things done&lt;/li&gt;
	&lt;li&gt;willingness to dive into an existing code base, fix stuff and extend existing functionality&lt;/li&gt;
	&lt;li&gt;good social skills&lt;/li&gt;
	&lt;li&gt;ability to speak English (German is a plus)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;#8217;re interested, send me your credentials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: the open position has been filled. Thanks for sending in your emails.&lt;/p&gt;</description>
        <pubDate>2007-06-06T16:20:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2007/06/06/rails-consultant-wanted</guid>
        <link>/blog/articles/2007/06/06/rails-consultant-wanted</link>
      </item>
    
      <item>
        <title>New Railsbench Release (0.9.2)</title>
        <description>&lt;p&gt;A new version of railsbench has been released. Benchmarking POST requests is now supported, benchmark specific session data can be specified in the benchmark config file and ERB can be used as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;added POST support:
&lt;pre class=&quot;code&quot;&gt;
    search:
      uri: /search
      method: post
      post_data: category=dessert
&lt;/pre&gt;
&lt;ul&gt;&lt;li&gt;method defaults to get&lt;/li&gt;&lt;li&gt;post_data will be url encoded by railsbench&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;allow specification of session_data in benchmarks.yml:
&lt;pre class=&quot;code&quot;&gt;
    benchmark_name:
      uri: /
      session_data:
         user_id: 1
      post_data: category=dessert
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;load benchmarks.yml using ERB. Example: retrieve login ids using Rails)
&lt;pre class=&quot;code&quot;&gt;
    admin_interface:
      uri: /admin
      session_data:
        user_id: &lt;%= User.find_by_name('admin').id %&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;use benchmark names instead of urls in raw data files,
  old files can be converted using script convert_raw_data_files.
  change was required by post support&lt;/li&gt;
&lt;li&gt;copy environments/production.rb to environments/benchmarking.rb,
  instead of providing a fixed one&lt;/li&gt;
&lt;li&gt;don't create a broken benchmarks.yml file when running railsbench install&lt;/li&gt;
&lt;li&gt;perf_plot and perf_plot_gc accept -geometry parameter,
  for exact dimensioning of the produced .png file&lt;/li&gt;
&lt;li&gt;use -font_size=12 for setting font size when generating graphs&lt;/li&gt;
&lt;li&gt;use 'perf_plot -colors=color1,color2,...' to get a different color set&lt;/li&gt;
&lt;li&gt;use 'perf_plot -out=name' to write graph to file 'name'&lt;/li&gt;
&lt;li&gt;new script perf_table: create a tabular overview of perf data&lt;/li&gt;
&lt;li&gt;added -colorize option to perf_html, which results in green and red
  backgrounds in the factor columns&lt;/li&gt;
&lt;li&gt;added -theme option to perf_plot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy benchmarking!&lt;/p&gt;

</description>
        <pubDate>2007-04-01T12:42:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2007/04/01/new-railsbench-release-0-9-2</guid>
        <link>/blog/articles/2007/04/01/new-railsbench-release-0-9-2</link>
      </item>
    
      <item>
        <title>Rails 1.2 Performance</title>
        <description>&lt;p&gt;Rails 1.2-stable is somewhat slower than Rails 1.1-stable,
especially on action cached pages. But the slowdown I measured is nowhere near
the numbers which have been reported by
&lt;a href=&quot;http://www.alrond.com/en/2007/jan/25/performance-test-of-6-leading-frameworks/&quot;&gt;others&lt;/a&gt;. In
fact, two recent patches to speed up session creation and pstore
session retrieval, have resulted in improved performance for one of
the benchmarked actions.&lt;/p&gt;

&lt;p&gt;The following performance data table shows the speed difference for
the fastest availabe configuration for the tested application.
&lt;/p&gt;

&lt;style type=&quot;text/css&quot;&gt;
&lt;!--
.perf_header, .perf_data, .perf_name { font-size:70%; padding-left:5px; padding-right:5px; }
.perf_header { text-align:center; vertical-align:top; font-weight:bold;}
.i { font-style:italic; }
.b { font-weight:bold; }
.c1 { background:#fff3df; }
.c2 { background:#dfedff; }
.factor { background:#efe0ef; }
.factor_red_alert { background:#CC303B; }
.factor_red { background:#FF6060; }
.factor_reddish { background:#FFA766; }
.factor_green_alert { background:#0B8900; }
.factor_green { background:#6AB788; }
.factor_greenish { background:#7FFFB0; }
.name { background:#dfdfdf; }
.perf_name   { text-align:left;   }
.perf_data   { text-align:right;  }
--&gt;
&lt;/style&gt;
&lt;div style=&quot;margin:10px;&quot;&gt;
&lt;table cellspacing=1px&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;empty                            &lt;/td&gt;
&lt;td class='perf_data c1'&gt;11.44034&lt;/td&gt;&lt;td class='perf_data c2'&gt;10.91962&lt;/td&gt;
&lt;td class='perf_data c1'&gt;437.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;457.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.29&lt;/td&gt;&lt;td class='perf_data c2'&gt;2.18&lt;/td&gt;
&lt;td class='perf_data factor_greenish'&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;welcome                          &lt;/td&gt;
&lt;td class='perf_data c1'&gt;13.04648&lt;/td&gt;&lt;td class='perf_data c2'&gt;14.29709&lt;/td&gt;
&lt;td class='perf_data c1'&gt;383.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;349.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.61&lt;/td&gt;&lt;td class='perf_data c2'&gt;2.86&lt;/td&gt;
&lt;td class='perf_data factor_reddish'&gt;0.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;recipes                          &lt;/td&gt;
&lt;td class='perf_data c1'&gt;10.83617&lt;/td&gt;&lt;td class='perf_data c2'&gt;13.51635&lt;/td&gt;
&lt;td class='perf_data c1'&gt;461.4&lt;/td&gt;&lt;td class='perf_data c2'&gt;369.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.17&lt;/td&gt;&lt;td class='perf_data c2'&gt;2.70&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;my_recipes                       &lt;/td&gt;
&lt;td class='perf_data c1'&gt;10.80137&lt;/td&gt;&lt;td class='perf_data c2'&gt;13.48035&lt;/td&gt;
&lt;td class='perf_data c1'&gt;462.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;370.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.16&lt;/td&gt;&lt;td class='perf_data c2'&gt;2.70&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;show                             &lt;/td&gt;
&lt;td class='perf_data c1'&gt;24.16722&lt;/td&gt;&lt;td class='perf_data c2'&gt;27.37878&lt;/td&gt;
&lt;td class='perf_data c1'&gt;206.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;182.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.83&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.48&lt;/td&gt;
&lt;td class='perf_data factor_red'&gt;0.88&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;cat                              &lt;/td&gt;
&lt;td class='perf_data c1'&gt;26.56038&lt;/td&gt;&lt;td class='perf_data c2'&gt;29.88683&lt;/td&gt;
&lt;td class='perf_data c1'&gt;188.3&lt;/td&gt;&lt;td class='perf_data c2'&gt;167.3&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.31&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.98&lt;/td&gt;
&lt;td class='perf_data factor_red'&gt;0.89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;cat_page5                        &lt;/td&gt;
&lt;td class='perf_data c1'&gt;27.24954&lt;/td&gt;&lt;td class='perf_data c2'&gt;30.78081&lt;/td&gt;
&lt;td class='perf_data c1'&gt;183.5&lt;/td&gt;&lt;td class='perf_data c2'&gt;162.4&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.45&lt;/td&gt;&lt;td class='perf_data c2'&gt;6.16&lt;/td&gt;
&lt;td class='perf_data factor_red'&gt;0.89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;letter                           &lt;/td&gt;
&lt;td class='perf_data c1'&gt;26.99067&lt;/td&gt;&lt;td class='perf_data c2'&gt;30.17507&lt;/td&gt;
&lt;td class='perf_data c1'&gt;185.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;165.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.40&lt;/td&gt;&lt;td class='perf_data c2'&gt;6.04&lt;/td&gt;
&lt;td class='perf_data factor_red'&gt;0.89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name i'&gt;all requests                    &lt;/td&gt;
&lt;td class='perf_data c1'&gt;151.09216&lt;/td&gt;&lt;td class='perf_data c2'&gt;170.43488&lt;/td&gt;
&lt;td class='perf_data c1'&gt;264.7&lt;/td&gt;&lt;td class='perf_data c2'&gt;234.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.78&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.26&lt;/td&gt;
&lt;td class='perf_data factor_red'&gt;0.89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;/tr&gt;&lt;tr&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left'&gt;GC statistics&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 #gc&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 #gc&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 gc%&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 #gc%&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;                                 &lt;/td&gt;
&lt;td class='perf_data c1'&gt;10.42790&lt;/td&gt;&lt;td class='perf_data c2'&gt;12.90426&lt;/td&gt;
&lt;td class='perf_data c1'&gt;120.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;135.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;6.90&lt;/td&gt;&lt;td class='perf_data c2'&gt;7.57&lt;/td&gt;
&lt;td class='perf_data factor_red_alert'&gt;0.81&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p style=&quot;font-size:80%;&quot;&gt;c1: 1.1-stable, c2: 1.2-stable, r/s: requests per second, ms/r: milliseconds per request&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Read the full report &lt;a href=&quot;/blog/files/reports/rails1.1-stable_vs_rails1.2-stable/report.html&quot;&gt;here&lt;/a&gt;.
&lt;/p&gt;

</description>
        <pubDate>2007-04-01T12:28:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2007/04/01/rails-1-2-performance</guid>
        <link>/blog/articles/2007/04/01/rails-1-2-performance</link>
      </item>
    
      <item>
        <title>Railsbench gem updated</title>
        <description>&lt;p&gt;Today I&amp;#8217;ve released a new gem version (0.9.1) of railsbench. It&amp;#8217;s mainly a bug fix release for the installation problems discovered for 0.9.0.&lt;/p&gt;
&lt;p&gt;However, there&amp;#8217;s also a new script called &lt;tt&gt;generate_benchmarks&lt;/tt&gt;, which can be used to generate and maintain the benchmark configuration file used by railsbench.&lt;/p&gt;
&lt;p&gt;&lt;tt&gt;railsbench generate_benchmarks&lt;/tt&gt; updates the benchmark configuration file with&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;a benchmark for each controller/action pair (named &amp;lt;controller&amp;gt;_&amp;lt;action&amp;gt;)&lt;/li&gt;
	&lt;li&gt;a benchmark for each controller combining all actions of the controller into one benchmark (named &amp;lt;controller&amp;gt;_controller)&lt;/li&gt;
	&lt;li&gt;a benchmark comprising all controllers (named all_controllers)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This should get you started benchmarking in no time ;-)&lt;/p&gt;
&lt;p&gt;After generating the file, you will need to edit the benchmarks and replace routing placeholders (&lt;tt&gt;:id&lt;/tt&gt;, &lt;tt&gt;:article_id&lt;/tt&gt;, etc.) by actual values.&lt;/p&gt;
&lt;p&gt;If you add new controllers/actions later in the development process, you can invoke &lt;tt&gt;railsbench generate_benchmarks&lt;/tt&gt; again to add new items to the configuration file. The older entries will not be removed by this process.&lt;/p&gt;
&lt;p&gt;Currently, &lt;tt&gt;generate_benchmarks&lt;/tt&gt; only works for the 1.2 release candidate and edge Rails (but I&amp;#8217;ll gladly accept patches to make it work with 1.1.6).&lt;/p&gt;
&lt;p&gt;Happy benchmarking!&lt;/p&gt;</description>
        <pubDate>2007-01-14T15:45:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2007/01/14/railsbench-gem-updated</guid>
        <link>/blog/articles/2007/01/14/railsbench-gem-updated</link>
      </item>
    
      <item>
        <title>Producing Performance Graphs</title>
        <description>&lt;p&gt;The latest version of railsbench contains scripts to convert raw performance data files into pretty pictures. They depend on rmagick and gruff to be installed on your system.&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
railsbench perf_plot &amp;lt;files&amp;gt;
&lt;/pre&gt;
&lt;p&gt;will generate a chart comparing benchmark data from all files passed as arguments.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div align=center&gt;
&lt;p&gt;&lt;a href=&quot;/blog/files/charts/chart1.png&quot; target=_blank&gt;&lt;img src=&quot;/blog/files/charts/chart1_small.png&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;</description>
        <pubDate>2006-12-26T19:16:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/12/26/producing-performance-graphs</guid>
        <link>/blog/articles/2006/12/26/producing-performance-graphs</link>
      </item>
    
      <item>
        <title>railsbench gem version available</title>
        <description>&lt;p&gt;railsbench is now available as a gem from RubyForge. I recommend all users to switch to the gem version. This move should make it much easier to maintain railsbench installations for a larger number of machines.&lt;/p&gt;
&lt;p&gt;Installation is now as simple as &lt;tt&gt;sudo gem install railsbench&lt;/tt&gt;. Or, if you have installed the 0.8.4 gem version: &lt;tt&gt;sudo gem update railsbench&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The gem release will install only one ruby driver script, named &lt;tt&gt;railsbench&lt;/tt&gt; in the default ruby path; individual commands like &lt;tt&gt;perf_run&lt;/tt&gt; etc. are accessible through this driver. So instead of typing&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
perf_run 100 &quot;-bm=all -mysql_session&quot;
&lt;/pre&gt;
&lt;p&gt;you would use&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
railsbench perf_run 100 &quot;-bm=all -mysql_session&quot;
&lt;/pre&gt;
&lt;p&gt;The &lt;tt&gt;perf_&lt;/tt&gt; command prefix is now optional, thus&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
railsbench run 100 &quot;-bm=all -mysql_session&quot;
&lt;/pre&gt;
&lt;p&gt;would give identical results.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re accustomed to the old syntax and find typing railsbench awkward, you could add the gem&amp;#8217;s script directory to your search path, by adding the following code to your shell profile:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
eval `railsbench path`; export PATH
&lt;/pre&gt;
&lt;p&gt;This will continue to work should you upgrade railsbench to a newer version.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; In order to call the scripts directly, you need to issue a &lt;tt&gt;sudo railsbench postinstall&lt;/tt&gt; command after installing the gem. I haven&amp;#8217;t found a way to create a gem that sets the executable bit on anything which lives outside the bin directory and isn&amp;#8217;t a binary executable.&lt;/p&gt;</description>
        <pubDate>2006-12-26T14:42:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/12/26/railsbench-gem-version-available</guid>
        <link>/blog/articles/2006/12/26/railsbench-gem-version-available</link>
      </item>
    
      <item>
        <title>On Premature Optimization</title>
        <description>&lt;p&gt;The alert reader of my blog might have noticed that I really care about performance. Some people even have accused me of being &amp;#8220;obsessed&amp;#8221; with it. Very often these statements are accompanied by Tony Hoare&amp;#8217;s famous line: &amp;#8220;Premature optimization is the root of all evil.&amp;#8221;, which was later repeated by Donald Knuth.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve always admired the work of Hoare and Knuth and I&amp;#8217;m well aware of the famous quote on premature optimization. And they&amp;#8217;re absolutely right: premature optimization is evil.&lt;/p&gt;
&lt;p&gt;However, what lots of people seem to miss out, is that the most important word in his statement is &amp;#8220;premature&amp;#8221;.&lt;/p&gt;
&lt;p&gt;If you don&amp;#8217;t give any consideration to performance, you will be sure to avoid premature optimization. But you might have made a design decision which simply cannot be reverted without huge cost at a later stage of the project.&lt;/p&gt;
&lt;p&gt;Let me give you an example: I once was asked to evaluate a project because it had performance problems. The software was intended to be used in a call center, which requires really fast response times. It turned out that the external company hired to implement this software, had made the decision to write the UI dialogs in a custom templating language, for which they had written an interpreter. The interpreter had been written in Visual Basic, which, at that time, was an interpreter as well.&lt;/p&gt;
&lt;p&gt;So in effect, the dialogs were running c1*c2 times slower than necessary, where c1 and c2 are the interpreter overheads. It&amp;#8217;s probably safe to assume the software ran about 25-50 times slower than necessary. And even top of the line hardware with 2 processors wasn&amp;#8217;t able to make the package run fast enough.&lt;/p&gt;
&lt;p&gt;In the end, the whole project was canceled, after pouring millions of &lt;span class=&quot;caps&quot;&gt;EUR&lt;/span&gt; into it. And the problem was solved by buying another call center wholesale. I still believe today, that if some consideration had been given to performance questions during the architectural design phase, this disaster could have been avoided.&lt;/p&gt;
&lt;p&gt;So, yes, premature optimization is evil, but no consideration for performance issues is just as bad.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; &lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt;, I was prompted to write this little piece after reading a &lt;a href=&quot;http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20.html&quot;&gt;blog entry&lt;/a&gt;&lt;br /&gt;
about a talk delivered at the Web 2.0 conference. It clearly shows that speed matters down to sub second resolution, even for web applications. I wouldn&amp;#8217;t be surprised, if a well known UI axiom gets proven to hold in web context as well: response time should be below 100ms for graphical user interfaces. Making it faster is almost unnoticeable to the end user, but slower than 100ms does have negative effects.&lt;/p&gt;</description>
        <pubDate>2006-11-10T08:01:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/11/10/on-premature-optimization</guid>
        <link>/blog/articles/2006/11/10/on-premature-optimization</link>
      </item>
    
      <item>
        <title>SqlSessionStore gains support for SQLite</title>
        <description>&lt;p&gt;Ted X Toth has submitted the code for a SQLite session class implementation for SqlSessionStore. I have checked it into the &lt;a href=&quot;http://railsexpress.de/svn/plugins/sql_session_store/trunk/lib/sqlite_session.rb&quot;&gt;subversion repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thank you very much Ted!&lt;/p&gt;</description>
        <pubDate>2006-11-09T12:37:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/11/09/sqlsessionstore-gains-support-for-sqlite</guid>
        <link>/blog/articles/2006/11/09/sqlsessionstore-gains-support-for-sqlite</link>
      </item>
    
      <item>
        <title>Make ruby-mysql create less garbage</title>
        <description>&lt;p&gt;During the preparation of my RailsConf2006 talk I did some comparative benchmarks with Mysql and Postgresql. To my astonishment, I observed that Rails with Mysql created many more objects. After digging into the C part of ruby bindings of Mysql, I discovered that the Mysql bindings create a copy of the columns name string for each record retrieved from the database. This obviously leads to quadratic memory use and calls for correction.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve written a small patch for the ruby-mysql bindings and submitted it to the author, but never got a response, although a tried several times.&lt;/p&gt;
&lt;p&gt;You can get the patch &lt;a href=&quot;/downloads/mysql-ruby-2.7-less-string-copies-in-each-hash.diff&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The patch actually goes a little farther than just correcting the n*m problem. I have added a &lt;tt&gt;Mysql::Result.all_hashes&lt;/tt&gt; method, so that the entire array of hashes creation runs in C.&lt;/p&gt;
&lt;p&gt;For pages that retrieve small datasets, you will probably see only a small increase. I measured around 5% increase for pages that load 25 objects. Which is neat. But the patch really shines when you retrieve large data sets. For example, for loading 1000 objects, I got this perf data:&lt;/p&gt;
&lt;style type=&quot;text/css&quot;&gt;
&lt;p&gt;&lt;!--
.perf_header, .perf_data, .perf_name { font-size:70%; padding-left:5px; padding-right:5px; }
.perf_header { text-align:center; vertical-align:top; font-weight:bold;}
.i { font-style:italic; }
.b { font-weight:bold; }
.c1 { background:#fff3df; }
.c2 { background:#dfedff; }
.factor { background:#efe0ef; }
.name { background:#dfdfdf; }
.perf_name   { text-align:left;   }
.perf_data   { text-align:right;  }
--&gt;&lt;/p&gt;
&lt;/style&gt;
&lt;table cellspacing=&quot;1px&quot; style=&quot;margin:10px&quot;&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/alphabetic&lt;/td&gt;
&lt;td class='perf_data c1'&gt;6.86126&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.20610&lt;/td&gt;
&lt;td class='perf_data c1'&gt;14.6&lt;/td&gt;&lt;td class='perf_data c2'&gt;19.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;68.61&lt;/td&gt;&lt;td class='perf_data c2'&gt;52.06&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;/tr&gt;&lt;tr&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left'&gt;GC statistics&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 #gc&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 #gc&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 gc%&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 #gc%&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;&lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.14250&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.18728&lt;/td&gt;
&lt;td class='perf_data c1'&gt;24.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;12.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;31.23&lt;/td&gt;&lt;td class='perf_data c2'&gt;22.81&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;30% faster!&lt;/p&gt;
&lt;p&gt;But more important, a lot less gargabe gets created (in the example GC runs twice as often with the unpatched bindings).&lt;/p&gt;
&lt;p&gt;You can take advantage of this by creating your own garbage ;-)&lt;/p&gt;</description>
        <pubDate>2006-10-05T19:56:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/10/05/make-ruby-mysql-create-less-garbage</guid>
        <link>/blog/articles/2006/10/05/make-ruby-mysql-create-less-garbage</link>
      </item>
    
      <item>
        <title>Oracle support for sql_session_store</title>
        <description>&lt;p&gt;Due to a contribution from Tiago Macedo, sql_session_store has gained &lt;a href=&quot;/plugins/trac/changeset/51&quot;&gt;Oracle support&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re on Oracle and want improved session handling performance, you should give it a try.&lt;/p&gt;
&lt;p&gt;If you find any problems, please submit bug reports/patches &lt;a href=&quot;/plugins/trac/newticket&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And if you now how to and have time to implement support for other database adapters, please send an email or better, create a ticket and attach the patch.&lt;/p&gt;</description>
        <pubDate>2006-10-05T16:38:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/10/05/oracle-support-for-sq_session_store</guid>
        <link>/blog/articles/2006/10/05/oracle-support-for-sq_session_store</link>
      </item>
    
      <item>
        <title>New plugin: query_builder</title>
        <description>&lt;p&gt;I&amp;#8217;ve added another plugin for you to check out: &lt;a href=&quot;/svn/plugins/query_builder/trunk&quot;&gt;query_builder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This plugin enables you to define finder methods that bypass the overhead of construct_finder_sql.&lt;/p&gt;

Inside an ActiveRecord model definition,
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;  &lt;span class=&quot;n&quot;&gt;define_finder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options_hash&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
will create a &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; query method called &lt;tt&gt;query_name&lt;/tt&gt; from a given &lt;tt&gt;options_hash&lt;/tt&gt;. &lt;tt&gt;query_type&lt;/tt&gt; can be &lt;tt&gt;:first&lt;/tt&gt; or &lt;tt&gt;:all&lt;/tt&gt;. The plugin supports all options except &lt;tt&gt;:include&lt;/tt&gt;, but ignores &lt;tt&gt;with_scope&lt;/tt&gt; options. Example:
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Recipe&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;define_finder&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:find_all_of_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;user = :user AND priv &amp;lt; :priv&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
This defines a query method which can be called like so:
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_all_of_user&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;martin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:priv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
This call is equivalent to
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;user = :user AND priv &amp;lt; :priv&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;martin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:priv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
If &lt;tt&gt;options[:positional]&lt;/tt&gt; is not &lt;tt&gt;nil&lt;/tt&gt; or &lt;tt&gt;false&lt;/tt&gt;, the created query
method will use positional paramaters instead of a hash. In this case, arguments are created in the order of appearance on the parameters passed to &lt;tt&gt;define_finder&lt;/tt&gt;. Therefore
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;define_finder&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:find_all_of_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;user = :user AND priv &amp;lt; :priv&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:positional&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
will create a query method with parameters &lt;tt&gt;user&lt;/tt&gt; and &lt;tt&gt;priv&lt;/tt&gt;, which can be
called like so:
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Recipes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_all_of_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;martin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I converted one of my pages to use this style and it gained 10% more performance.&lt;/p&gt;
&lt;p&gt;If you like this plugin, drop me a line. If you find a bug, please submit a bug report to &lt;a href=&quot;/plugins/trac&quot;&gt;Trac&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Enjoy.&lt;/p&gt;

</description>
        <pubDate>2006-09-23T06:33:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/09/23/new-plugin-query_builder</guid>
        <link>/blog/articles/2006/09/23/new-plugin-query_builder</link>
      </item>
    
      <item>
        <title>Piggy back plugin updated</title>
        <description>&lt;p&gt;Timo Hentschel, one of my coworkers at the company for which I’m doing contract work at the moment (&lt;a href=&quot;http://www.autoscout24.de&quot;&gt;AutoScout24&lt;/a&gt;), has added a nifty little extension to my &lt;a href=&quot;/svn/plugins/piggy_back/trunk&quot;&gt;piggy_back plugin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s now possible to piggy back from &lt;tt&gt;has_many :through&lt;/tt&gt; associations, provided the association will return at most one record from the underlying &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; query.&lt;/p&gt;
&lt;p&gt;This type of association currently needs to be used as a replacement for the non existent &lt;tt&gt;has_one :through&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;There have been rumours that &lt;tt&gt;has_one :through&lt;/tt&gt; will find it&amp;#8217;s way into rails core. If it does, I&amp;#8217;ll probably remove the &lt;tt&gt;has_many :through support&lt;/tt&gt; from piggy back plugin again, or at least raise a deprecation warning.&lt;/p&gt;</description>
        <pubDate>2006-09-16T10:42:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/09/16/piggy-back-plugin-updated</guid>
        <link>/blog/articles/2006/09/16/piggy-back-plugin-updated</link>
      </item>
    
      <item>
        <title>SqlSessionStore now available as a plugin</title>
        <description>&lt;p&gt;Rails core team member Rick Olson, the author of many rails plugins, &lt;a href=&quot;http://mephistoblog.com/&quot;&gt;mephisto&lt;/a&gt; and &lt;a href=&quot;http://rails.techno-weenie.net/&quot;&gt;techno-weenie&lt;/a&gt;, has turned &lt;a href=&quot;/blog/articles/2005/12/19/roll-your-own-sql-session-store&quot;&gt;SQLSessionStore&lt;/a&gt; into a plugin and sent his code for me to publish. Thanks a lot Rick!&lt;/p&gt;
&lt;p&gt;I incorporated the latest changes from my sql session store implementation, most notably postgresql support, and added sql_session_store to my &lt;a href=&quot;/plugins/trac&quot;&gt;trac installation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using sql_session_store is now easier than ever before. Check it out into your &lt;tt&gt;vendor/plugins&lt;/tt&gt; directory:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;
svn co http://railsexpress.de/svn/plugins/sql_session_store/trunk  \
 sql_session_store
&lt;/pre&gt;
&lt;p&gt;and follow the instructions in the &lt;a href=&quot;/svn/plugins/sql_session_store/trunk/README&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you find any problems with the plugin, which would be entirely my own fault, not Rick&amp;#8217;s, please use Trac to report them.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt;, I’d love to get support in for additional database adapters, especially Oracle. I you find the time to write an adapter, please submit the code using Trac, or email me.&lt;/p&gt;</description>
        <pubDate>2006-09-15T09:56:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/09/15/sqlsessionstore-now-available-as-a-plugin</guid>
        <link>/blog/articles/2006/09/15/sqlsessionstore-now-available-as-a-plugin</link>
      </item>
    
      <item>
        <title>Rails Template Optimizer Beta Test</title>
        <description>&lt;p&gt;It's there. Finally. Get it while it's still hot. Be among the first to experience unprecedented rendering speed for Rails Erb templates ;-)&lt;/p&gt;

&lt;p&gt;We all know and love the little helpers that Rails offers to speed up template coding. They're convenient and help us to keep the template code readable. But convenience almost always comes with a hidden performance cost. It's an unavoidable fact, at least in the IT business.&lt;/p&gt;

&lt;p&gt;I started the Rails Template Optimizer project in order to reduce the hidden cost in using Rails helper methods. And I think the current version of this software shows that this is possible, to a great extent, although it is still in a beta state.&lt;/p&gt;

&lt;p&gt;You can download the code from subversion. Since I'm pretty sure that there are still some bugs and problems with the code, I have set up a &lt;a href=&quot;/plugins/trac&quot;&gt;Trac installation&lt;/a&gt;. The start page contains information on how to obtain the template optimizer and links to additional information.&lt;/p&gt;

&lt;p&gt;So, how does it work? And what kind of performance improvement can you expect?&lt;/p&gt;

&lt;p&gt;Very early during my involvement in Rails performance improvement I observed that some of the Rails helpers would run rather slowly, most notably helpers that use route generation in some form. I worked around the problem by coding my own specialized methods (as decribed in my &lt;a href=&quot;http://www.infoq.com/articles/Rails-Performance&quot;&gt;InfoQ article&lt;/a&gt; to avoid invoking the routing code at all. This was acceptable for my own purposes, but not really usable for larger applications, with complicated route setups. In addition, some of the helpers, especially those that create AJAX code, produce code so complicated that it would be insane to write it manually.&lt;/p&gt;

&lt;p&gt;But after thinking about the problem for a while it dawned on me that a good part of the work the helpers were doing could be done once and for all at template compile time:&lt;/p&gt;

&lt;p&gt;First, there are helper calls that have either no argument or all of their arguments specfied in the template code. These can safely evaluated when the template gets compiled. (Well, most of the time, the actual story is a bit more complicated than that. Use the source to find out more.)&lt;/p&gt;

&lt;p&gt;Second, there are helper calls where the output produced depends to a large extent on the structure of the input data, and only slightly on the exact value of that data.&lt;/p&gt;

&lt;p&gt;Consider the following link_to call:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Edit User&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;edit&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;user_link&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Assuming just the default routes, we know that this will always produce&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/user/edit/#{@user.to_param}&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;user_link&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Edit User&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And this is exactly the code that will be produced by the template optimizer at template compile time. It achieves this by performing a partial (symbolic) evaluation of the template code. (For details I'd like to refer you to the source code, for now.)&lt;/p&gt;

&lt;p&gt;How much improvement will you get by using the optimizer? That's a tough question. It all depends on the actual source and may vary between no improvement at all and spectacular improvements.&lt;/p&gt;

&lt;p&gt;As usual, I've benchmarked it. Here are two data sets. First, my own app with every link using link_to instead of my helpers.&lt;/p&gt;

&lt;table cellspacing=1px style=&quot;margin-top:10px;margin-bottom:10px&quot;&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/show/413                  &lt;/td&gt;
&lt;td class='perf_data c1'&gt;8.15451&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.23208&lt;/td&gt;
&lt;td class='perf_data c1'&gt;122.6&lt;/td&gt;&lt;td class='perf_data c2'&gt;191.1&lt;/td&gt;
&lt;td class='perf_data c1'&gt;8.15&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.23&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise           &lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.85367&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.68909&lt;/td&gt;
&lt;td class='perf_data c1'&gt;101.5&lt;/td&gt;&lt;td class='perf_data c2'&gt;213.3&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.85&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.69&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise?page=5   &lt;/td&gt;
&lt;td class='perf_data c1'&gt;10.10721&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.84142&lt;/td&gt;
&lt;td class='perf_data c1'&gt;98.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;206.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;10.11&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.84&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/letter/G                  &lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.86153&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.67950&lt;/td&gt;
&lt;td class='perf_data c1'&gt;101.4&lt;/td&gt;&lt;td class='perf_data c2'&gt;213.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.86&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.68&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.11&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;Second, the admin interface of an older Typo version:&lt;/p&gt;

&lt;table cellspacing=1px style=&quot;margin-top:10px;margin-bottom:10px&quot;&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin                            &lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.49967&lt;/td&gt;&lt;td class='perf_data c2'&gt;0.85967&lt;/td&gt;
&lt;td class='perf_data c1'&gt;66.7&lt;/td&gt;&lt;td class='perf_data c2'&gt;116.3&lt;/td&gt;
&lt;td class='perf_data c1'&gt;15.00&lt;/td&gt;&lt;td class='perf_data c2'&gt;8.60&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.74&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin/content                    &lt;/td&gt;
&lt;td class='perf_data c1'&gt;7.01567&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.84333&lt;/td&gt;
&lt;td class='perf_data c1'&gt;14.3&lt;/td&gt;&lt;td class='perf_data c2'&gt;54.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;70.16&lt;/td&gt;&lt;td class='perf_data c2'&gt;18.43&lt;/td&gt;
&lt;td class='perf_data factor'&gt;3.81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin/pages                      &lt;/td&gt;
&lt;td class='perf_data c1'&gt;2.99467&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.31767&lt;/td&gt;
&lt;td class='perf_data c1'&gt;33.4&lt;/td&gt;&lt;td class='perf_data c2'&gt;75.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;29.95&lt;/td&gt;&lt;td class='perf_data c2'&gt;13.18&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin/categories                 &lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.51033&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.12500&lt;/td&gt;
&lt;td class='perf_data c1'&gt;22.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;32.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;45.10&lt;/td&gt;&lt;td class='perf_data c2'&gt;31.25&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.44&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin/sidebar                    &lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.88533&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.04133&lt;/td&gt;
&lt;td class='perf_data c1'&gt;20.5&lt;/td&gt;&lt;td class='perf_data c2'&gt;24.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;48.85&lt;/td&gt;&lt;td class='perf_data c2'&gt;40.41&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin/themes                     &lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.58300&lt;/td&gt;&lt;td class='perf_data c2'&gt;2.29667&lt;/td&gt;
&lt;td class='perf_data c1'&gt;27.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;43.5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;35.83&lt;/td&gt;&lt;td class='perf_data c2'&gt;22.97&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/admin/users                      &lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.41167&lt;/td&gt;&lt;td class='perf_data c2'&gt;0.77100&lt;/td&gt;
&lt;td class='perf_data c1'&gt;70.8&lt;/td&gt;&lt;td class='perf_data c2'&gt;129.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;14.12&lt;/td&gt;&lt;td class='perf_data c2'&gt;7.71&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.83&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;I would say these examples show some really nice improvement factors.&lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;You can svn co from http://railsexpress.de/svn/plugins/template_optimizer/trunk&lt;/p&gt;

&lt;p&gt;And the template optimizer should now be compatible with rails 1.1.6&lt;/p&gt;
</description>
        <pubDate>2006-08-15T23:01:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/08/15/rails-template-optimizer-beta-test</guid>
        <link>/blog/articles/2006/08/15/rails-template-optimizer-beta-test</link>
      </item>
    
      <item>
        <title>RailsConf2006 Aftermath</title>
        <description>&lt;p&gt;As promised during my talk at RailsConf, I have uploaded a new version of my railsbench package to rubyforge. You can either download the &lt;a href=&quot;http://rubyforge.org/frs/download.php/11282/railsbench-0.8.2.tar.gz&quot;&gt;tar ball&lt;/a&gt; or get the new version using svn. Apologies to all users which have a checked out and modified version of the old CVS archive. I decided to convert from CVS to subversion since I kept typing svn commands at my CVS archive, so it had to go.&lt;/p&gt;

&lt;p&gt;The svn url for railsbench is &lt;tt&gt;svn://rubyforge.org//var/svn/railsbench/trunk/railsbench&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;The new version now supports running &lt;tt&gt;&lt;a href=&quot;http://rubyforge.org/projects/ruby-prof&quot;&gt;ruby-prof&lt;/a&gt;&lt;/tt&gt; as an alternative to SVL's &lt;a href=&quot;http://www.softwareverify.com/ruby/profiler/index.html&quot;&gt;Ruby Performance Validator&lt;/a&gt;. This should make some Mac and Linux users happy. However, &lt;tt&gt;ruby-prof&lt;/tt&gt; is only a weak substitute for a good profiler.&lt;/p&gt;

&lt;p&gt;Profiling with &lt;tt&gt;ruby-prof&lt;/tt&gt; requires ruby 1.8.4 and works like this:&lt;/p&gt;
&lt;p style=&quot;margin-left:10px&quot;&gt;
&lt;tt&gt;
perf_prof &lt;i&gt;n&lt;/i&gt; &quot;-bm=&lt;i&gt;benchmark_name&lt;/i&gt; &lt;i&gt;other_options&lt;/i&gt;&quot; &lt;i&gt;config_name&lt;/i&gt;
&lt;/tt&gt;
&lt;/p&gt;

&lt;p&gt;This will run the named benchmark &lt;i&gt;n&lt;/i&gt; times using &lt;tt&gt;ruby-prof&lt;/tt&gt; and store the resulting HTML formatted profiler graph into &lt;tt&gt;$RAILS_PERF_DATA&lt;/tt&gt;&lt;/p&gt;

&lt;p style=&quot;margin-top:10px;margin-bottom:10px&quot;&gt;Happy profiling!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;PS:&lt;/b&gt; My presentation given at RailsConf2006 is &lt;a href=&quot;/blog/files/slides/railsconf2006.pdf&quot;&gt;available for download&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>2006-06-28T16:25:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/06/28/railsconf2006-aftermath</guid>
        <link>/blog/articles/2006/06/28/railsconf2006-aftermath</link>
      </item>
    
      <item>
        <title>Common Rails Performance Problems</title>
        <description>&lt;p&gt;InfoQ has published an article on &lt;a href=&quot;http://www.infoq.com/articles/Rails-Performance&quot;&gt;common Rails performance problems&lt;/a&gt; (written by me). You can head over to read all about it.&lt;/p&gt;</description>
        <pubDate>2006-06-13T23:17:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/06/13/common-rails-performance-problems</guid>
        <link>/blog/articles/2006/06/13/common-rails-performance-problems</link>
      </item>
    
      <item>
        <title>Simpler Piggy Backing</title>
        <description>&lt;p&gt;A while ago I posted an &lt;a href=&quot;/blog/articles/2005/11/06/the-case-for-piggy-backed-attributes&quot;&gt;article &lt;/a&gt; about the performance improvements obtainable by piggy backing. Although the speedups where substantial, I received some negative comments about exposing too much SQL to the programmer.&lt;/p&gt;

&lt;p&gt;Exposure to the underlying SQL is not such a big problem for me, that it would deter me from applying the technique. But I found that I had a lot of repetition in my code, which I didn't like.&lt;/p&gt;

&lt;p&gt;After ignoring the problem for a while, I decided it was about time to deliver a better solution than manually coding selects and joins.&lt;/p&gt;

&lt;p&gt;I wrote a small extension to ActiveRecord, which makes piggy backing extremely simple.&lt;/p&gt;

&lt;p&gt;Instead of coding joins and selects manually, you can now declare the piggy backed attributes from a has_one or belongs_to association in your model classes like so:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Article&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;piggy_back&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user_name_and_birthday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:birthday&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This will generate all necessary select and join statements, which can then be added to a query rather elegantly:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:piggy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user_name_and_birthday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;articles.title LIKE &amp;#39;%piggy%&amp;#39;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;would retrieve the first article which contains 'piggy' in its title attribute, along with the &lt;tt&gt;birthday&lt;/tt&gt; and &lt;tt&gt;name&lt;/tt&gt; attributes of the corresponding &lt;tt&gt;User&lt;/tt&gt; object, storing them in the attributes hash of the AR instance.&lt;/p&gt;

&lt;p&gt;But this is not all! After declaring the piggy backed attributes, you will also get reader methods which retrieve the attribute for you from the AR instance, and, should a type cast be required, convert the value to the correct type.&lt;/p&gt;

&lt;p&gt;The piggy backed attributes are accessed like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_name&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;==&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_birthday&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;==&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;date&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Additionally, should you forget to piggy back a query,&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;articles.title LIKE &amp;#39;%piggy%&amp;#39;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;methods &lt;tt&gt;user_name&lt;/tt&gt; and &lt;tt&gt;birthday&lt;/tt&gt; will silently use the &lt;tt&gt;user&lt;/tt&gt; association to retrieve the values for you. This make is possible to use &lt;tt&gt;user_name&lt;/tt&gt; and &lt;tt&gt;user_birthday&lt;/tt&gt; regardless of whether your original query was piggy backed or not.&lt;/p&gt;

&lt;p&gt;I've ensured that all of this works with pagination. In fact, using the extension is slightly faster than coding the select and joins manually (1%-3%).&lt;/p&gt;

&lt;p&gt;You can download the code &lt;a href=&quot;/downloads/piggy_back.rb&quot;&gt;here&lt;/a&gt;. I haven't turned it into a plugin yet, so you need to add a &lt;tt&gt;require 'piggy_back'&lt;/tt&gt; to your &lt;tt&gt;environment.rb&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I failed to mention that piggy backing also works with finds on associations, so&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:piggy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;works as expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upon popular demand it's now possible to use a more verbose syntax. You can write&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Article&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;piggy_back&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user_name_and_birthday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:birthday&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;for the example above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Piggy backing is now available as a plugin using the URL &lt;tt&gt;svn://railsexpress.de/plugins/piggy_back/trunk&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>2006-05-29T12:06:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/05/29/simpler-piggy-backing</guid>
        <link>/blog/articles/2006/05/29/simpler-piggy-backing</link>
      </item>
    
      <item>
        <title>Ruby en Rails 2006</title>
        <description>&lt;p&gt;Next week, there&amp;#8217;s a Rails conference in the Netherlands, &lt;a href=&quot;http://www.profict.nl/ruby&quot;&gt;Ruby en Rails 2006&lt;/a&gt;, were I will present my wisdom about Rails performance tuning. If you live nearby, and haven&amp;#8217;t registered yet, now&amp;#8217;s your last chance!&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m sure it will prove to be a very interesting event. I&amp;#8217;m especially looking forward to hear about a Ruby.net implementation project, presented by &lt;a href=&quot;http://www.wilcob.com/Wilco/Default.aspx&quot;&gt;Wilco Bauwer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And, of course I anticipate the after conference event, where we should have plenty of time to relax and dream up new ideas to save the world from joyless programming!&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; I must say this was a very well organized event at a beautyful location, were I&amp;#8217;ve met very nice people. It was a real pleasure to be there.&lt;/p&gt;
&lt;p&gt;My slides are now &lt;a href=&quot;/blog/files/slides/rubyenrails2006.pdf&quot;&gt;available for download&lt;/a&gt;.&lt;/p&gt;</description>
        <pubDate>2006-05-11T17:24:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/05/11/ruby-en-rails-2006</guid>
        <link>/blog/articles/2006/05/11/ruby-en-rails-2006</link>
      </item>
    
      <item>
        <title>Performance related changes in Rails 1.1</title>
        <description>&lt;p&gt;In addition to being packed with &lt;a href=&quot;http://weblog.rubyonrails.com/articles/2006/03/28/rails-1-1-rjs-active-record-respond_to-integration-tests-and-500-other-things&quot;&gt;new features&lt;/a&gt; and also some &lt;a href=&quot;http://clarkware.com/cgi/blosxom/2006/03/28#Rails11&quot;&gt;forgotten ones&lt;/a&gt;, the recently released &lt;a href=&quot;http://www.rubyonrails.org/down&quot;&gt;Rails 1.1&lt;/a&gt; contains a number of performance related changes. For some cases, you will see significant improvements.&lt;/p&gt;

&lt;p&gt;The &lt;b&gt;components implementation&lt;/b&gt; received a complete refactoring, making it both faster and simpler to use.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
inside a controller you can easily determine whether your current action is being run on behalf of an embedding controller by calling &lt;tt&gt;component_request?&lt;/tt&gt;
&lt;/li&gt;
&lt;li&gt;
session and flash information will now be passed on from the embedding controller to the component. As a consequence, it is no longer necessary to save session information to the session container before a component action is invoked by the embedding controller. For pages embedding &lt;i&gt;n&lt;/i&gt; components, this saves &lt;i&gt;n&lt;/i&gt; session queries and updates, reducing DB load significantly if you use ActiveRecordStore or &lt;a href=&quot;/blog/articles/2005/12/19/roll-your-own-sql-session-store&quot;&gt;MysqlSessionStore&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;It is also possible to specify the controller as a class constant, bypassing the inflector code to compute the controller class at runtime. So
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;render_component&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;greeter&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hello_world&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
becomes
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;render_component&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GreeterController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hello_world&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Due to the component refactoring, it is no longer necessary to save newly created sessions twice. This has the biggest impact for people using ActiveRecodStore.&lt;/p&gt;

&lt;p&gt;We have &lt;b&gt;changed the default&lt;/b&gt; for &lt;tt&gt;ActiveRecord::Base.allow_concurrency&lt;/tt&gt; from &lt;tt&gt;true&lt;/tt&gt; to &lt;tt&gt;false&lt;/tt&gt;, since almost all apps run in a single threaded request container. In addition, you can now safely set &lt;tt&gt;ActiveRecord::Base.allow_concurrency&lt;/tt&gt; in &lt;tt&gt;environment.rb&lt;/tt&gt; or any other config file.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Connection cache management&lt;/b&gt; got a serious overhaul. Previously, the connection cache was emptied after each request, in order to solve problems with dropped database connections. You can now use &lt;b&gt;lazy connection verification&lt;/b&gt; by setting &lt;tt&gt;ActiveRecord::Base.verification_timeout&lt;/tt&gt; to a number of seconds timeout interval. It defaults to &lt;it&gt;0&lt;/it&gt;, to be compatible with the previous release. However, I strongly recommend setting it to a higher value, for a simple reason:
&lt;blockquote&gt;
Dropped database connections occur mostly on sites not seeing traffic for the database internal connection timeout period. High traffic sites will see them rarely. However, for high traffic sites, reducing the number of database accesses by setting &lt;tt&gt;verification_timeout&lt;/tt&gt; to a value slightly below the database internal value will result in a significant reduction of DB requests. For example, if you use memcached for session management, the DB won't see any hit for action cached pages.
&lt;/blockquote&gt;

&lt;p&gt;Additionally, the &lt;b&gt;connection cache size&lt;/b&gt; was reduced from the number of ActiveRecord classes involved in a query, to the number of active database connections. So for most applications this means that instead of retrieving and verifying &lt;i&gt;n&lt;/i&gt; connections, &lt;b&gt;at most 1 retrieval and verification will occur&lt;/b&gt;, and only when the timeout interval has passed.&lt;/p&gt;

&lt;p style=&quot;margin-top:10px&quot;&gt;&lt;b&gt;Update:&lt;/b&gt; the correct way of determining whether you're in a component request is calling &lt;tt&gt;component_request?&lt;/tt&gt;. In a view you can call &lt;tt&gt;controller.component_request?&lt;/tt&gt; 

</description>
        <pubDate>2006-04-03T17:52:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/04/03/performance-related-changes-in-rails-1-1</guid>
        <link>/blog/articles/2006/04/03/performance-related-changes-in-rails-1-1</link>
      </item>
    
      <item>
        <title>Rails 1.1 Release</title>
        <description>&lt;p&gt;As you probably know already, Rails 1.1 was released a few days ago.&lt;/p&gt;
&lt;p&gt;We have worked hard to ensure that 1.1 performs on the same level as 1.0. For some cases, it performs significantly better than 1.0 (explanation will follow in a future post).&lt;/p&gt;
&lt;p&gt;The following performance data table shows the speed difference for the fastest available configuration for my application.&lt;/p&gt;
&lt;table cellspacing=&quot;1&quot; style=&quot;margin-bottom:10px;&quot;&gt;
&lt;tr&gt;
&lt;th class=&quot;perf_header name&quot; style=&quot;text-align: left;&quot;&gt;page&lt;/th&gt;
&lt;th class=&quot;perf_header c1&quot;&gt;c1 total&lt;/th&gt;&lt;th class=&quot;perf_header c2&quot;&gt;c2 total&lt;/th&gt;
&lt;th class=&quot;perf_header c1&quot;&gt;c1 r/s&lt;/th&gt;&lt;th class=&quot;perf_header c2&quot;&gt;c2 r/s&lt;/th&gt;
&lt;th class=&quot;perf_header c1&quot;&gt;c1 ms/r&lt;/th&gt;&lt;th class=&quot;perf_header c2&quot;&gt;c2 ms/r&lt;/th&gt;
&lt;th class=&quot;perf_header factor&quot;&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/empty/index&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;7.86139&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;7.10545&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;636.0&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;703.7&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.57&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.42&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/welcome/index&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;8.38743&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;8.32744&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;596.1&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;600.4&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.68&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.67&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/index&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;8.87038&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;8.75717&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;563.7&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;571.0&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.77&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.75&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/myknzlpzl&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;8.86172&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;8.76325&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;564.2&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;570.6&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.77&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.75&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/show/713&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;22.22530&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;20.12046&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;225.0&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;248.5&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.45&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.02&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/cat/Hauptspeise&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;25.29051&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;24.70123&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;197.7&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;202.4&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;5.06&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.94&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/cat/Hauptspeise?page=5&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;25.92528&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;25.40904&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;192.9&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;196.8&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;5.19&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;5.08&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/letter/G&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;25.06242&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;24.96315&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;199.5&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;200.3&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;5.01&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.99&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You can find additional information and lots of performance data in the &lt;a href=&quot;/blog/files/reports/rails1.0_vs_rails1.1/report.html&quot;&gt;full report&lt;/a&gt; .&lt;/p&gt;</description>
        <pubDate>2006-03-30T19:25:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/03/30/rails-1-1-release</guid>
        <link>/blog/articles/2006/03/30/rails-1-1-release</link>
      </item>
    
      <item>
        <title>Presenting at RailsConf 2006</title>
        <description>&lt;p&gt;I&amp;#8217;m proud to announce that I will be giving a talk at &lt;a href=&quot;http://railsconf.org&quot;&gt;RailsConf2006&lt;/a&gt; on &lt;a href=&quot;http://railsconf.org/talks/selected/show/166&quot;&gt;Rails Application Optimization&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have specific topics or questions you&amp;#8217;d like to have addressed besides the ones mentioned in the talk proposal, or some general suggestion, I invite you to add an entry to the comment section of this post.&lt;/p&gt;
&lt;p&gt;Looking forward to meet you in Chicago!&lt;/p&gt;</description>
        <pubDate>2006-03-28T09:51:00+02:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/03/28/presenting-at-railsconf-2006</guid>
        <link>/blog/articles/2006/03/28/presenting-at-railsconf-2006</link>
      </item>
    
      <item>
        <title>Using memcached for Ruby on Rails session storage</title>
        <description>&lt;p&gt;A few days ago Eric Hodel announced the availability of a new pure Ruby memcached client implementation (&lt;a href=&quot;http://rubyforge.org/frs/?group_id=1266&quot;&gt;memcache-client-1.0.3&lt;/a&gt;) with performance improvements over the older &lt;a href=&quot;http://raa.ruby-lang.org/project/memcache/&quot;&gt;Ruby-Memcache-0.4&lt;/a&gt; implementation.&lt;/p&gt;
&lt;p&gt;I had measured the old version previously, for use as a Ruby on Rails fragment cache storage container, but found its performance to be abysmal and completely unusable for my purposes.&lt;/p&gt;
&lt;p&gt;memcache-client-1.0.3 provides much better performance: much faster than either the old implementation, pstore or ActiveRecordStore, but also faster than my optimized SQLSessionStore using MysqlSession (see &lt;a href=&quot;/blog/articles/2005/12/19/roll-your-own-sql-session-store&quot;&gt;Roll your own &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; session store&lt;/a&gt;).&lt;br /&gt;
In order to determine the relative performance I ran my &lt;a href=&quot;/blog/pages/usual_benchmarks.html&quot;&gt;usual benchmarks&lt;/a&gt; using &lt;a href=&quot;http://railsbench.rubyforge.org/&quot;&gt;railsbench&lt;/a&gt; against memcache-client-1.0.3 and SQLSessionStore using MyslSession.&lt;/p&gt;
&lt;p&gt;All components resided on a single machine. Before running the tests, both DB tables and memcached were populated with 10000 sessions.&lt;/p&gt;
&lt;p&gt;The first test was run with Mysql query caching disabled:&lt;/p&gt;
&lt;table cellspacing=&quot;1px&quot; style=&quot;margin-top:4px;margin-bottom:12px;&quot;&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/empty/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.23318&lt;/td&gt;&lt;td class='perf_data c2'&gt;0.96322&lt;/td&gt;
&lt;td class='perf_data c1'&gt;810.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;1038.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.23&lt;/td&gt;&lt;td class='perf_data c2'&gt;0.96&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/welcome/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.44314&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.15051&lt;/td&gt;
&lt;td class='perf_data c1'&gt;692.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;869.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.44&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.15&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.52869&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.19616&lt;/td&gt;
&lt;td class='perf_data c1'&gt;654.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;836.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.53&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.20&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/myknzlpzl&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.52159&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.19022&lt;/td&gt;
&lt;td class='perf_data c1'&gt;657.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;840.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.52&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.19&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/show/713&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.14906&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.95939&lt;/td&gt;
&lt;td class='perf_data c1'&gt;241.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;252.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.15&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.96&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.48101&lt;/td&gt;&lt;td class='perf_data c2'&gt;9.29202&lt;/td&gt;
&lt;td class='perf_data c1'&gt;105.5&lt;/td&gt;&lt;td class='perf_data c2'&gt;107.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.48&lt;/td&gt;&lt;td class='perf_data c2'&gt;9.29&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise?page=5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.84404&lt;/td&gt;&lt;td class='perf_data c2'&gt;9.65393&lt;/td&gt;
&lt;td class='perf_data c1'&gt;101.6&lt;/td&gt;&lt;td class='perf_data c2'&gt;103.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.84&lt;/td&gt;&lt;td class='perf_data c2'&gt;9.65&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/letter/G&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.42370&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.20227&lt;/td&gt;
&lt;td class='perf_data c1'&gt;184.4&lt;/td&gt;&lt;td class='perf_data c2'&gt;192.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.42&lt;/td&gt;&lt;td class='perf_data c2'&gt;5.20&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;font-size:75%;text-align:left&quot; colspan=&quot;8&quot;&gt;&amp;nbsp;c1: DB sessions, c2: memcached sessions, r/s: requests per second, ms/r: milliseconds per request&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;On the second run, Mysql query caching was enabled:&lt;/p&gt;
&lt;table cellspacing=&quot;1px&quot; style=&quot;margin-top:4px;margin-bottom:12px&quot;&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/empty/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.26804&lt;/td&gt;&lt;td class='perf_data c2'&gt;0.95403&lt;/td&gt;
&lt;td class='perf_data c1'&gt;788.6&lt;/td&gt;&lt;td class='perf_data c2'&gt;1048.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.27&lt;/td&gt;&lt;td class='perf_data c2'&gt;0.95&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/welcome/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.47070&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.13807&lt;/td&gt;
&lt;td class='perf_data c1'&gt;679.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;878.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.47&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.14&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.29&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.55976&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.18066&lt;/td&gt;
&lt;td class='perf_data c1'&gt;641.1&lt;/td&gt;&lt;td class='perf_data c2'&gt;847.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.56&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.18&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/myknzlpzl&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.55402&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.17650&lt;/td&gt;
&lt;td class='perf_data c1'&gt;643.5&lt;/td&gt;&lt;td class='perf_data c2'&gt;850.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.55&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.18&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/show/713&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.50876&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.20310&lt;/td&gt;
&lt;td class='perf_data c1'&gt;285.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;312.2&lt;/td&gt;
&lt;td class='perf_data c1'&gt;3.51&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.20&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.31720&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.00799&lt;/td&gt;
&lt;td class='perf_data c1'&gt;231.6&lt;/td&gt;&lt;td class='perf_data c2'&gt;249.5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.32&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.01&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.08&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise?page=5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.41150&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.11811&lt;/td&gt;
&lt;td class='perf_data c1'&gt;226.7&lt;/td&gt;&lt;td class='perf_data c2'&gt;242.8&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.41&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.12&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/letter/G&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.31190&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.02345&lt;/td&gt;
&lt;td class='perf_data c1'&gt;231.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;248.5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.31&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.02&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;font-size:75%;text-align:left&quot; colspan=&quot;8&quot;&gt;&amp;nbsp;c1: DB sessions, c2: memcached sessions, r/s: requests per second, ms/r: milliseconds per request&lt;/td&gt;
&lt;/table&gt;
&lt;p&gt;What can we learn from this data?&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Pages which force the creation of new sessions (empty, welcome) and action cached pages (rezept/index and rezept/knzlpzl) experience a speedup between 25% and 33%.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Pages involving DB queries other than session retrieval don&amp;#8217;t see as much speedup.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;If query caching is disabled and the query is really DB expensive (/rezept/cat issues a &lt;span class=&quot;caps&quot;&gt;LIKE&lt;/span&gt; &lt;span&gt;%Hauptspeise&lt;/span&gt;%), the speed improvement is negligible.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Enabling the Mysql query cache will result in slightly slower creation of new sessions, but can speed up complex queries tremendously (table below).&lt;/li&gt;
&lt;/ul&gt;
&lt;table cellspacing=&quot;1px&quot;  style=&quot;margin-top:4px;margin-bottom:12px&quot;&gt;
&lt;tr&gt;
&lt;th class='perf_header name' style='text-align:left;'&gt;page&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 total&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 total&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 r/s&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 r/s&lt;/th&gt;
&lt;th class='perf_header c1'&gt;c1 ms/r&lt;/th&gt;&lt;th class='perf_header c2'&gt;c2 ms/r&lt;/th&gt;
&lt;th class='perf_header factor'&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/empty/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.23318&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.26804&lt;/td&gt;
&lt;td class='perf_data c1'&gt;810.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;788.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.23&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.27&lt;/td&gt;
&lt;td class='perf_data factor'&gt;0.97&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/welcome/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.44314&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.47070&lt;/td&gt;
&lt;td class='perf_data c1'&gt;692.9&lt;/td&gt;&lt;td class='perf_data c2'&gt;679.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.44&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.47&lt;/td&gt;
&lt;td class='perf_data factor'&gt;0.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/index&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.52869&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.55976&lt;/td&gt;
&lt;td class='perf_data c1'&gt;654.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;641.1&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.53&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.56&lt;/td&gt;
&lt;td class='perf_data factor'&gt;0.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/myknzlpzl&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.52159&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.55402&lt;/td&gt;
&lt;td class='perf_data c1'&gt;657.2&lt;/td&gt;&lt;td class='perf_data c2'&gt;643.5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;1.52&lt;/td&gt;&lt;td class='perf_data c2'&gt;1.55&lt;/td&gt;
&lt;td class='perf_data factor'&gt;0.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/show/713&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.14906&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.50876&lt;/td&gt;
&lt;td class='perf_data c1'&gt;241.0&lt;/td&gt;&lt;td class='perf_data c2'&gt;285.0&lt;/td&gt;
&lt;td class='perf_data c1'&gt;4.15&lt;/td&gt;&lt;td class='perf_data c2'&gt;3.51&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.48101&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.31720&lt;/td&gt;
&lt;td class='perf_data c1'&gt;105.5&lt;/td&gt;&lt;td class='perf_data c2'&gt;231.6&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.48&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.32&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/cat/Hauptspeise?page=5&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.84404&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.41150&lt;/td&gt;
&lt;td class='perf_data c1'&gt;101.6&lt;/td&gt;&lt;td class='perf_data c2'&gt;226.7&lt;/td&gt;
&lt;td class='perf_data c1'&gt;9.84&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.41&lt;/td&gt;
&lt;td class='perf_data factor'&gt;2.23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class='perf_name name'&gt;/rezept/letter/G&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.42370&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.31190&lt;/td&gt;
&lt;td class='perf_data c1'&gt;184.4&lt;/td&gt;&lt;td class='perf_data c2'&gt;231.9&lt;/td&gt;
&lt;td class='perf_data c1'&gt;5.42&lt;/td&gt;&lt;td class='perf_data c2'&gt;4.31&lt;/td&gt;
&lt;td class='perf_data factor'&gt;1.26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;font-size:75%;text-align:left&quot; colspan=&quot;8&quot;&gt;&amp;nbsp;c1: DB sessions without query cache, c2: DB sessions with query cache&lt;/td&gt;
&lt;/table&gt;
&lt;p&gt;Like all benchmarks, these results have to be taken with a grain of salt. Choice of either option involves more than just looking at the above numbers.&lt;/p&gt;
&lt;p&gt;Database and memcached have quite different scaling properties: adding more memcached daemons is easy, whereas DB based session storage scales mostly by buying a bigger DB machine or running the session DB on a separate machine using a session database.&lt;/p&gt;
&lt;p&gt;On the other hand, DB session storage makes it easy to get application usage statistics using &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; queries, e.g. displaying the number of active sessions or checking whether a particular user is currently logged in. I don&amp;#8217;t know an easy way to do this using the memcachd &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;It seems to me that using memcached for session storage is a good choice if your DB server experiences a very high load and your scaling options are already exhausted. I wouldn&amp;#8217;t recommend to use it per default.&lt;/p&gt;
&lt;p&gt;Using memcachd for Ruby on Rails fragment cache storage is a completely different story, on which I hope to report in the future.&lt;/p&gt;</description>
        <pubDate>2006-01-24T12:42:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2006/01/24/using-memcached-for-ruby-on-rails-session-storage</guid>
        <link>/blog/articles/2006/01/24/using-memcached-for-ruby-on-rails-session-storage</link>
      </item>
    
      <item>
        <title>French translation of Railsexpress articles</title>
        <description>&lt;p&gt;Tremeur Balbous &lt;a href=&quot;http://tremeur.balbous.free.fr/index.php/?p=77&quot;&gt;has translated&lt;/a&gt; some of my blog articles into French. You can find them on &lt;a href=&quot;http://www.railsfrance.org/node/147&quot;&gt;www.railsfrance.org&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;This is great news, for me, and the French Rails community.&lt;/p&gt;
&lt;p&gt;Merci beaucoup, Tremeur.&lt;/p&gt;

</description>
        <pubDate>2005-12-27T13:19:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/12/27/french-translation-of-railsexpress-articles</guid>
        <link>/blog/articles/2005/12/27/french-translation-of-railsexpress-articles</link>
      </item>
    
      <item>
        <title>Roll your own SQL session store</title>
        <description>&lt;p&gt;The alert reader may have noticed that I'm using my own SQL session store, which provides &lt;b&gt;much&lt;/b&gt; better performance than the default ActiveRecordStore shipping with Rails.&lt;/p&gt;

&lt;p&gt;I have decided to publish the source code &lt;a href=&quot;/downloads/sql_session_store_0.1.tar.gz&quot;&gt;here&lt;/a&gt;. If you are using Mysql, simply unpack the files into your lib directory and make SQLSessionStore your session storage.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sql_session_store&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mysql_session&amp;#39;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CgiRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DEFAULT_SESSION_OPTIONS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:database_manager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SQLSessionStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;SQLSessionStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MysqlSession&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

If you're using components, which you probably shouldn't, you'll need to activate eager session saving:
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;MysqlSession&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eager_session_creation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The improved performance is due to a number of factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fixed number of known DB columns&lt;/li&gt;
&lt;li&gt;retrieve only fields into the session that are actually used to create the session for a controller&lt;/li&gt;
&lt;li&gt;offloading most of the work to the DB, including updating the &lt;tt&gt;created_at&lt;/tt&gt; and &lt;tt&gt;updated_at&lt;/tt&gt; fields&lt;/li&gt;
&lt;li&gt;hard coded Mysql statements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a consequence, if you want another DB, other DB column names, don't want &lt;tt&gt;created_at &lt;/tt&gt; or &lt;tt&gt;updated_at&lt;/tt&gt; fields, you'll have to change the code.&lt;/p&gt;

&lt;p&gt;I have uploaded HTML representations of the call trees for &lt;a href=&quot;/blog/files/calltrees/slow_sessions.html&quot;&gt;ActiveRecordStore&lt;/a&gt; and &lt;a href=&quot;/blog/files/calltrees/fast_sessions.html&quot;&gt;SQLSessionStore&lt;/a&gt;. If you inspect them closely, you'll see how much time ActiveRecordStore spends in just creating the SQL statements and how much simpler the call tree is for SQLSessionStore.&lt;/p&gt;

&lt;p&gt;If you adapt the provided code for other database systems, I'd be happy if you sent me the code, and I'll add it to the download after reviewing. The required changes are probably pretty small, but I currently don't have the time to test other DB systems.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

</description>
        <pubDate>2005-12-19T10:30:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/12/19/roll-your-own-sql-session-store</guid>
        <link>/blog/articles/2005/12/19/roll-your-own-sql-session-store</link>
      </item>
    
      <item>
        <title>Rails 1.0 Release</title>
        <description>&lt;p&gt;It's party time! &lt;a href=&quot;http://weblog.rubyonrails.com/articles/2005/12/13/rails-1-0-party-like-its-one-oh-oh&quot;&gt;Rails 1.0 hit the streets&lt;/a&gt; this week.&lt;/p&gt;

&lt;p&gt;Somehow I didn't manage to release a performance report on the new release on the very same day, as planned ..., but here it is.&lt;/p&gt;

&lt;p&gt;Rails 1.0 performs &lt;a href=&quot;/blog/files/reports/r0.14.1_vs_r1.0/1-on-1-comparisons.html&quot;&gt;slightly worse&lt;/a&gt; than the previous 0.14.1
release for my application. However, 1.0 is still &lt;a href=&quot;/blog/files/reports/r0.13.1_vs_r0.14.1/report.html&quot;&gt;much faster&lt;/a&gt; than the
0.13 release series.&lt;/p&gt;

&lt;p&gt;The following performance data table shows the speed difference for
the fastest available configuration for the tested application.
&lt;/p&gt;

&lt;table cellspacing=&quot;1&quot; style=&quot;margin-left:10px;margin-bottom:10px;&quot;&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th class=&quot;perf_header name&quot; style=&quot;text-align: left;&quot;&gt;page&lt;/th&gt;
&lt;th class=&quot;perf_header c1&quot;&gt;c1 total&lt;/th&gt;&lt;th class=&quot;perf_header c2&quot;&gt;c2 total&lt;/th&gt;
&lt;th class=&quot;perf_header c1&quot;&gt;c1 r/s&lt;/th&gt;&lt;th class=&quot;perf_header c2&quot;&gt;c2 r/s&lt;/th&gt;
&lt;th class=&quot;perf_header c1&quot;&gt;c1 ms/r&lt;/th&gt;&lt;th class=&quot;perf_header c2&quot;&gt;c2 ms/r&lt;/th&gt;
&lt;th class=&quot;perf_header factor&quot;&gt;c1/c2&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/empty/index&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.26111&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.40676&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;793.0&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;710.9&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.26&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.41&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/welcome/index&lt;/td&gt;

&lt;td class=&quot;perf_data c1&quot;&gt;1.41814&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.57333&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;705.1&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;635.6&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.42&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.57&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/index&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.50077&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.66533&lt;/td&gt;

&lt;td class=&quot;perf_data c1&quot;&gt;666.3&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;600.5&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.50&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.67&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/myknzlpzl&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;1.49374&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.65309&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;669.5&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;604.9&lt;/td&gt;

&lt;td class=&quot;perf_data c1&quot;&gt;1.49&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;1.65&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/show/713&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;3.59988&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;3.99798&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;277.8&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;250.1&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;3.60&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.00&lt;/td&gt;

&lt;td class=&quot;perf_data factor&quot;&gt;0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/cat/Hauptspeise&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.54024&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.86669&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;220.3&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;205.5&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.54&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.87&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.93&lt;/td&gt;

&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;perf_name name&quot;&gt;/rezept/cat/Hauptspeise?page=5&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.64729&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.97066&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;215.2&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;201.2&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.65&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.97&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.93&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;

&lt;td class=&quot;perf_name name&quot;&gt;/rezept/letter/G&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.59054&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.84387&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;217.8&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;206.4&lt;/td&gt;
&lt;td class=&quot;perf_data c1&quot;&gt;4.59&lt;/td&gt;&lt;td class=&quot;perf_data c2&quot;&gt;4.84&lt;/td&gt;
&lt;td class=&quot;perf_data factor&quot;&gt;0.95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;font-size:75%;text-align:left&quot; colspan=&quot;8&quot;&gt;&amp;nbsp;c1: 0.14.1, c2: 1.0, r/s: requests per second, ms/r: milliseconds per request&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The reasons for this significant slowdown have been identified and
are being worked on (tickets &lt;a href=&quot;http://dev.rubyonrails.org/ticket/3155&quot;&gt;3155&lt;/a&gt; and &lt;a href=&quot;http://dev.rubyonrails.org/ticket/3174&quot;&gt;3174&lt;/a&gt;).
&lt;/p&gt;

You can find additional information and lots of performance data in the &lt;a href=&quot;/blog/files/reports/r0.14.1_vs_r1.0/report.html&quot;&gt;full report&lt;/a&gt;.

</description>
        <pubDate>2005-12-18T20:44:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/12/18/rails-1-0-release</guid>
        <link>/blog/articles/2005/12/18/rails-1-0-release</link>
      </item>
    
      <item>
        <title>Trim your output</title>
        <description>&lt;p&gt;The 0.14 Rails series includes a new option setting for template rendering, which allows for reducing the number of newlines generated by template processing. It's a string valued class attribute for &lt;tt&gt;ActionView&lt;/tt&gt;, called &lt;tt&gt;erb_trim_mode&lt;/tt&gt;. Its value is passed to the ERB compiler when a template gets compiled, with a default value of &lt;tt&gt;&quot;-&quot;&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt; &lt;a href=&quot;http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html#M000684&quot;&gt;Some documentation&lt;/a&gt; for possible settings is part of the &lt;a href=&quot;http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/&quot;&gt;ERB class doc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
However, the doc is incomplete, as it doesn't mention Rails' default setting &lt;tt&gt;&quot;-&quot;&lt;/tt&gt;.
&lt;/p&gt;
&lt;p&gt;&lt;tt&gt;erb_trim_mode&lt;/tt&gt; affects the way template processing handles newline characters in the template. Per default, (when &lt;tt&gt;erb_trim_mode&lt;/tt&gt; is set to nil), processing leaves &lt;b&gt;all&lt;/b&gt; newline characters occurring in the template in the generated html code. Which means that many extraneous newlines get inserted into your output.&lt;/p&gt;

&lt;p&gt;For example,
&lt;pre class=&quot;code&quot;&gt;
&lt;% if expr %&gt;
some text
&lt;% else %&gt;
other text
&lt;% end %&gt;
&lt;/pre&gt;
will generate the following processing code:
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;some text&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;other text&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;With the default setting of &lt;tt&gt;erb_trim_mode&lt;/tt&gt;, you can suppress extraneous newline characters by adding a &lt;tt&gt;-&lt;/tt&gt; before the closing &lt;tt&gt;%&amp;gt;&lt;/tt&gt;:

&lt;pre class=&quot;code&quot;&gt;
&lt;% if expr -%&gt;
some text
&lt;% else -%&gt;
other text
&lt;% end -%&gt;
&lt;/pre&gt;

will generate the following template code:

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;some text&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_erbout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;other text&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;This version looks much cleaner, suppresses 2 superfluous newline characters in the generated HTML code and saves 2 function calls when processed. Which is no big deal, unless the above call occurs inside a loop. If the loop body gets executed 100 times, you have already saved 200 characters and, more importantly, 200 function calls.&lt;/p&gt;

&lt;p&gt;Manually adding all the minuses to closing &lt;tt&gt;%&amp;gt;&lt;/tt&gt; markup is somewhat tedious. &lt;tt&gt;erb_trim_mode&lt;/tt&gt; comes to rescue: if set to &lt;tt&gt;&quot;&amp;gt;&quot;&lt;/tt&gt;, newline characters will be suppressed for &lt;tt&gt;&amp;lt;%...%&amp;gt;&lt;/tt&gt; markup closing a line; if set to &lt;tt&gt;&quot;&amp;lt;&amp;gt;&quot;&lt;/tt&gt;, newline characters will be suppressed for &lt;tt&gt;&amp;lt;%...%&amp;gt;&lt;/tt&gt; occurring as a line of its own.
&lt;/p&gt;

&lt;p&gt;I have measured the relative performance of setting &lt;tt&gt;erb_trim_mode&lt;/tt&gt; to &lt;tt&gt;&quot;&amp;gt;&quot;&lt;/tt&gt;. The following table shows that my app's pages receive a performance increase ranging from 1 to 4%.

&lt;pre&gt;
configuration 1: 12-06.uncached.untrimmed
  requests=1000, options=-bm=uncached -lib=r141 -mysql_session
                         -fast_routes -fast_readers

configuration 2: 12-06.uncached.trimmed
  requests=1000, options=-bm=uncached -lib=r141 -mysql_session
                         -fast_routes -fast_readers -trim

page   c1 real   c2 real  c1 r/s  c2 r/s   c1 ms/r  c2 ms/r  c1/c2
 1:    3.52722   3.47518   283.5   287.8      3.53     3.48   1.01
 2:    4.30330   4.26213   232.4   234.6      4.30     4.26   1.01
 3:    4.49761   4.36027   222.3   229.3      4.50     4.36   1.03
 4:    4.45229   4.27840   224.6   233.7      4.45     4.28   1.04

urls:
 1: /rezept/show/713
 2: /rezept/cat/Hauptspeise
 3: /rezept/cat/Hauptspeise?page=5
 4: /rezept/letter/G
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Unfortunately, ERB doesn't support combining the &lt;tt&gt;&quot;-&quot;&lt;/tt&gt; and &lt;tt&gt;&quot;&amp;gt;&quot;&lt;/tt&gt; setting. So you'll have to decide which way to go upfront. If you choose on &lt;tt&gt;&quot;&amp;gt;&quot;&lt;/tt&gt;, you may find that you have to add empty lines in some places where they weren't needed before.&lt;/p&gt;
</description>
        <pubDate>2005-12-06T01:13:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/12/06/trim-your-output</guid>
        <link>/blog/articles/2005/12/06/trim-your-output</link>
      </item>
    
      <item>
        <title>Don't load stuff you don't need</title>
        <description>Using Rails 0.14 and onward, you can give your app a slight performance boost by not loading parts of the framework that you don't need. For example, if you don't expose parts of your app as a web service, then you don't need to load &lt;tt&gt;actionwebservice&lt;/tt&gt;. Likewise, if you don't send mail from your app, you don't need to load &lt;tt&gt;actionmailer&lt;/tt&gt;.

If you're using the Rails initializer to start your app, you can do it like so:

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Initializer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Skip frameworks you&amp;#39;re not going to use&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frameworks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action_web_service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action_mailer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

If you're still using an old &lt;tt&gt;environment.rb&lt;/tt&gt;, just comment out the corresponding require lines:

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;# Require Rails libraries.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;active_support&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;active_record&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;action_controller&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# require &amp;#39;action_mailer&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# require &amp;#39;action_web_service&amp;#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

Additionally, you should also load only the database adapters for the database(s) which you are using. Add the following to your &lt;tt&gt;environment.rb&lt;/tt&gt;, before Rails gets required:

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;RAILS_CONNECTION_ADAPTERS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w(mysql)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

By default, Rails will load all connection adapters it can find.

Minimizing your code footprint will speed up Rails, because Ruby traverses all abstract syntax trees stored on the heap during garbage collection. If you can avoid loading significantly sized code, you will reduce the memory footprint of your app, thereby speeding up garbage collection. It might also help to increase object lookup at runtime due to smaller sized data structures containing meta information.

</description>
        <pubDate>2005-11-28T23:27:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/28/dont-load-stuff-you-dont-need</guid>
        <link>/blog/articles/2005/11/28/dont-load-stuff-you-dont-need</link>
      </item>
    
      <item>
        <title>Speeding up the creation of new sessions</title>
        <description>There's a tiny peculiarity in the &lt;tt&gt;cgi/session.rb&lt;/tt&gt;, which slows down the creation of new sessions quite a bit. The library &lt;tt&gt;digest/md5&lt;/tt&gt; gets required on creation of new sessions in method &lt;tt&gt;create_new_id&lt;/tt&gt;. This can be rather expensive to execute. Move the require line to the beginning of the file, and your session creation will run faster. In environments where require is really slow, it can make a big difference (almost &lt;b&gt;3 times faster&lt;/b&gt;), as you can see from this data:

&lt;pre&gt;
perf data file 1: 11-22.new.md5_unfixed
  requests=1000, options=-bm=new_sessions 
perf data file 2: 11-22.new.md5_fixed
  requests=1000, options=-bm=new_sessions

page              c1 real   c2 real    r/s    r/s   ms/r   ms/r  c1/c2
/empty/index      7.07800   2.39067  141.3  418.3   7.08   2.39   2.96
/welcome/index    7.07800   2.65100  141.3  377.2   7.08   2.65   2.67
&lt;/pre&gt;

On my Linux machine, the difference is less pronounced, but still significant:

&lt;pre&gt;
page              c1 real   c2 real    r/s    r/s   ms/r   ms/r  c1/c2
/empty/index      1.47967   1.25513  675.8  796.7   1.48   1.26   1.18
/welcome/index    1.63819   1.41946  610.4  704.5   1.64   1.42   1.15
&lt;/pre&gt;

Maybe the require was placed inside function &lt;tt&gt;create_new_id&lt;/tt&gt; to avoid loading the &lt;tt&gt;digest/md5&lt;/tt&gt; package in CGI environments when the request already passes a session id. But since Rails will usually run under FCGI/SCGI, moving it surely doesn't hurt!

If you also have Ruby CGI apps running on the same machine, you can copy the file into your load path for Rails and modify this copy instead.

</description>
        <pubDate>2005-11-22T04:13:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/22/speeding-up-the-creation-of-new-sessions</guid>
        <link>/blog/articles/2005/11/22/speeding-up-the-creation-of-new-sessions</link>
      </item>
    
      <item>
        <title>Components may not be evil, but they sure can be slow</title>
        <description>&lt;p&gt;Let me start with a confession: I've been ignoring Rails components for a while, as I just couldn't figure out what they where good for. Meaning of course, that I didn't need them for my application ;-)&lt;/p&gt;

&lt;p&gt;However, after DHH posted &lt;a href=&quot;http://weblog.rubyonrails.com/articles/2005/11/11/why-engines-and-components-are-not-evil-but-distracting&quot;&gt;his opinions&lt;/a&gt; on components on the Rails weblog, I thought I'd better a have a closer look, what they could do for me and also inspect their implementation details. Additionally, I discovered that Typo uses components to display various parts of the front page of my blog. And it seemed pretty slow at doing that. So I smelled a performance rat.&lt;/p&gt;

&lt;p&gt;Basically, components enable you to capture the presentation logic of a controller and embed it into another controller. This is implemented by duplicating the current request object, starting all over with request processing, capturing the rendering results and embedding them in the page that called &lt;img src=&quot;http://api.rubyonrails.com/classes/ActionController/Components.html#M000034&quot; alt=&quot;render_component&quot; /&gt; in the first place.&lt;/p&gt;

&lt;p&gt;This comprises creating a new controller object, in order enable request processing, and a new view object for template rendering. This already sounded like it wouldn't be particularly efficient, but the results I got, after creating a benchmark configuration for my blog and running railsbench to get some performance data, were shocking.
Here's my benchmark data:&lt;/p&gt;

&lt;pre class=&quot;perfdata&quot;&gt;
page request                            total  stddev%     r/s    ms/r
1:/                                  14.86220   0.1405    6.73  148.62
2:/articles/2005/11/08/accelera...   13.83662   0.1071    7.23  138.37
3:/admin                              1.47821   0.9429   67.65   14.78
4:/admin/content                      2.95742   0.2235   33.81   29.57
5:/admin/pages                        2.33728   0.0951   42.78   23.37
6:/admin/categories                   2.09189   0.2452   47.80   20.92
7:/admin/sidebar                     13.99597   0.9474    7.14  139.96
8:/admin/themes                       5.44847   0.3377   18.35   54.48
9:/admin/users                        1.48696   1.0194   67.25   14.87
&lt;/pre&gt;


&lt;p&gt;Page / measures the main blog page, the second entry measures a single article, and the remaining entries present data on the blog's admin interface.&lt;/p&gt;

&lt;p&gt;I just couldn't believe my eyes. Only &lt;b&gt;6.7&lt;/b&gt; requests per second to generate my blogs entry page? Unbelievable (on an Athlon 64 3000+). Especially since my own app runs over 200 requests per second on the same box.&lt;/p&gt;

&lt;p&gt;After studying call patterns using &lt;a href=&quot;http://www.softwareverify.com/rubyPerformanceValidator/&quot;&gt;Ruby Performance Validator&lt;/a&gt;, which is a really good tool for this task btw., I found out that Typo was loading its configuration from the database several times per request. It also tried to figure out the current page's feed url just as often. That seemed awfully wasteful of resources.&lt;/p&gt;

&lt;p&gt;The repetitions of the aforementioned actions were caused by 2 before filters installed on the application controller:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before_filter&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:reload_settings&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before_filter&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:auto:discovery_defaults&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;reload_settings&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reload&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto_discovery_defaults&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;auto_discovery_feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;feed&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto_discovery_feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:only_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;feed&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
               &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;xml&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_rss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rss20&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_atom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;atom10&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And sidebar content (archive, flickr, tada, etc.) gets delivered through components, which are all derived from ApplicationController, thus inheriting the filters. Bingo!&lt;/p&gt;

&lt;p&gt;There are, of course, several ways to fix this problem, I chose the simplest one, taking advantage of the fact that the request object passed to components gets duplicated for component processing. Upon entering the controller responsible for the request, config will be loaded and a processing flag is stored as an instance variable in the request object. Similarly, the values retrieved during feed get stored there as well. When a component gets invoked it retrieves these values from the request object.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;reload_settings&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_variable_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@config_reloaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@config_reloaded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reload&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;auto_discovery_defaults&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_rss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_variable_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_rss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_atom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
       &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_variable_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_rss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_atom&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;auto_discovery_feed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;feed&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_rss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                    &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_rss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance_variable_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                    &lt;span class=&quot;vi&quot;&gt;@auto_discovery_url_atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Running railsbench again and comparing the results shows that the most important pages are now rendered 4 to 5 times as fast:&lt;/p&gt;

&lt;pre class=&quot;perfdata&quot;&gt;
page    c1 real   c2 real  c1 r/s  c2 r/s  c1 ms/r  c2 ms/r  c1/c2
1:     14.86220   3.75458     6.7    26.6   148.62    37.55   3.96
2:     13.83662   2.70294     7.2    37.0   138.37    27.03   5.12
3:      1.47821   1.29960    67.6    76.9    14.78    13.00   1.14
4:      2.95742   2.71447    33.8    36.8    29.57    27.14   1.09
5:      2.33728   2.13827    42.8    46.8    23.37    21.38   1.09
6:      2.09189   1.73313    47.8    57.7    20.92    17.33   1.21
7:     13.99597   2.73185     7.1    36.6   139.96    27.32   5.12
8:      5.44847   1.42805    18.4    70.0    54.48    14.28   3.82
9:      1.48696   1.15061    67.3    86.9    14.87    11.51   1.29
&lt;/pre&gt;


&lt;p&gt;&lt;small&gt;Note: c1 and c2 label data of the original/modified application. r/s are requests per second and ms/r are milliseconds per request.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Now that's some niiiiiice improvement!&lt;/p&gt;

&lt;p&gt;I think that it's pretty easy to shoot oneself in the foot using components. I tend to avoid them. But sometimes they can be nice, in that case: watch out for da slow filters! Either don't derive the components from &lt;tt&gt;ApplicationController&lt;/tt&gt;, make sure that the filters are fast, possibly using the technique presented in this article, or turn them off completely, e.g. if you don't really need to run them and or can get at the necessary data using some other technique.&lt;/p&gt;

&lt;p&gt;The possibility to disable filters in derived controller classes was &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/Filters/ClassMethods.html&quot;&gt;recently added&lt;/a&gt; to Rails. So we could have said&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;  &lt;span class=&quot;n&quot;&gt;skip_before_filter&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:reload_config&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;on the component classes, instead of storing a flag inside the request object. It should be even faster than storing flags on the request object, because the filter will be removed from the filter chain during class load time. Maybe I'll measure that at a later time.&lt;/p&gt;
</description>
        <pubDate>2005-11-18T12:11:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/18/components-may-not-be-evil-but-they-sure-can-be-slow</guid>
        <link>/blog/articles/2005/11/18/components-may-not-be-evil-but-they-sure-can-be-slow</link>
      </item>
    
      <item>
        <title>Accelerate your dates</title>
        <description>&lt;p&gt;When I started work on improving my app's speed, I noticed that on pages that display lots of date information, a large percentage of CPU time was spent on formatting date strings. I added a quick fix to my code, was satisifed and quickly forgot about it.&lt;/p&gt;

&lt;p&gt;But recently I read a message on the ruby talk mailing list, where someone more or less rejected Rails after writing a small Ruby program for log file analysis that ran for about 27 minutes on a 100MB log file and a literally translated Java program finished in only 2.5 minutes &lt;a href=&quot;http://www.pankaj-k.net/archives/2005/11/ruby_or_java_a.html&quot;&gt;blog entry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It turned out that the inefficiency of the Ruby script was caused by the Ruby Date class, as someone rewrote the program using regexps to parse date info that needed only 3 minutes to complete the task.&lt;/p&gt;

&lt;p&gt;I'm pretty sure that the Date class performance could be much improved, for example by rewriting it in C, but we'll leave this to the ruby core team. For page speedup we simply resort to avoiding construction of Date objects altogether.
For Mysql, the Rails database layer will always return date information as strings. The strings are formatted as 'YYYY-mm-dd', i.e. they will have ISO date format. Such a string can of course be turned into 'dd.mm.YYYY' easily using Ruby primitives. So instead of writing&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strftime&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;dd.mm.YYYY&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;or&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;we'll change this into&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;created_at_formatted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;and add a function &lt;tt&gt;created_at_formatted&lt;/tt&gt; to our model, which will access the attributes hash directly and transform the string into our desired format. One possible way to code this function is&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;created_at_formatted&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;created_at&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;another is&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;created_at_formatted&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;created_at&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^(\d\d\d\d)-(\d\d)-(\d\d)/&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vg&quot;&gt;$3&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vg&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vg&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This assumes that &lt;tt&gt;created_at&lt;/tt&gt; is a non null column. If it isn't, you'll need to add some guards for null values.&lt;/p&gt;

&lt;p&gt;The first version comes out slightly faster than the second, which I expected. But how much faster than the original code?&lt;/p&gt;

&lt;p&gt;On pages with 25 dates displayed it is &lt;a href=&quot;/blog/pages/faster_date_display.html&quot;&gt;approximately 70%&lt;/a&gt; faster than the original version. On a page with 1 date, it's already 6% faster.&lt;/p&gt;

&lt;p&gt;If you have pages with a large number of date displays, you might consider this technique to make them a tad snappier :-)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; As mentioned by henri, the technique does not apply to the oracle adapter, as it returns Time objects. As time permits I will look into the other adapters, to find the &quot;bad boys&quot; which return strings.&lt;/p&gt;
</description>
        <pubDate>2005-11-09T00:49:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/09/accelerate-your-dates</guid>
        <link>/blog/articles/2005/11/09/accelerate-your-dates</link>
      </item>
    
      <item>
        <title>The case for piggy backed attributes</title>
        <description>&lt;p&gt;If you're subscribed to the rails mailing list, you might have seen some people talking about piggy backing attributes onto SQL queries.&lt;/p&gt;

&lt;p&gt;This is a feature of the Active Record ORM mapping that I like very much, because it can be used to speedup you queries enormously. And I hope it won't be eliminated, ever.&lt;/p&gt;

&lt;p&gt;Suppose there's a 1:n relationship between models A and B, i.e., for each A record there's exactly one B record (think B owns A). In my case that would be recipes and users.&lt;/p&gt;

&lt;p&gt;In ActiveRecord you'd have class declarations like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:recipes&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Recipe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Your usual code to retrieve some recipes with their associated authors will probably look like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;show_some&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@recipes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;with the show_some template being rendered implicitely and looking similar to:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;% for &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@recipes&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;  &amp;lt;%= r.title %&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;  &amp;lt;br&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;% end &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;There's nothing wrong with this code, except that it's kind of slow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;there will be 51 queries to the database, because for each recipe the owning user (author) will be fetched in a separate query&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;all these queries are constructed dynamically upon calling &lt;tt&gt;r.user.name&lt;/tt&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;We can do a little better than that: since approx. 0.13.1 Rails supports fetching associated objects by specifying our intention to access them via the :include syntax for find (called &lt;a href=&quot;http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html&quot;&gt;eager loading of associations&lt;/a&gt;).
So we'd actually write our query like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;show_some&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@recipes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:include&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;But how much faster is this? The answer is: it depends. On how fast DB access is, for example. Whether your DB lives on another host, network speed, etc.&lt;/p&gt;

&lt;p&gt;For a simple installation on one box, I have measured this (using &lt;a href=&quot;http://railsbench.rubyforge.org&quot;&gt;railsbench&lt;/a&gt;, 1000 requests each, patched GC):&lt;/p&gt;

&lt;pre&gt;
page request               total  stddev%     r/s    ms/r
/rezept/some_default    17.83765   0.2579    56.1   17.84
/rezept/some_include    13.25508   0.3499    75.4   13.26
&lt;/pre&gt;


&lt;p&gt;Speedup is 34%, which is OK, but not spectacular.&lt;/p&gt;

&lt;p&gt;We can do better than that using piggy backed attributes. First, we'll change the query to:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;no&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;r.user_id=u.id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:joins&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;r, users u&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;r.*, u.name AS user_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We still have only one query to the DB, this time involving a join, which could be slow. But don't worry, databases were constructed to perform such queries as fast as possible.&lt;/p&gt;

&lt;p&gt;In addition to the recipe columns we now get 'user_name' included in the retrieved records. To make access to this attribute fast, we'll add a user_name function to our model:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Recipe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;user_name&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;user_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;and change our template to:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;% for &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@recipes&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;  &amp;lt;%= r.title %&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_name&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sx&quot;&gt;  &amp;lt;br&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;% end &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Is this faster? Answer: you can bet!&lt;/p&gt;

&lt;pre&gt;
page request               total  stddev%     r/s    ms/r
/rezept/some_default    17.83765   0.2579    56.1   17.84
/rezept/some_include    13.25508   0.3499    75.4   13.26
/rezept/some_piggy       4.19032   0.1059   238.6    4.19
&lt;/pre&gt;


&lt;p&gt;It's whopping 4 times faster than the first version. And 3 times faster than the :include version.&lt;/p&gt;

&lt;p&gt;I can almost hear you scream &quot;But this code sucks! The original version was sooo much nicer. I hate adding this extra function to my model.&quot; My answer is: if your app is fast enough for you, don't do it. If it isn't, this is a nice opportunity for speedup.&lt;/p&gt;

&lt;p&gt;Also, if your rails app lives in a shared hosting environment, it means being nice to everyone else to make it faster.&lt;/p&gt;

&lt;p&gt;And if you weren't looking for speed, you wouldn't be reading this blog in the first place ;-)&lt;/p&gt;
</description>
        <pubDate>2005-11-06T20:35:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/06/the-case-for-piggy-backed-attributes</guid>
        <link>/blog/articles/2005/11/06/the-case-for-piggy-backed-attributes</link>
      </item>
    
      <item>
        <title>session :off !</title>
        <description>&lt;p&gt;Rails 0.14 contains the possibility to &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionController/SessionManagement/ClassMethods.html&quot;&gt;turn off sessions&lt;/a&gt; on a controller or even action basis.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WelcomeController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:off&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This will turn off session creation and update on all actions of class WelcomeController.&lt;/p&gt;

&lt;p&gt;Depending on the complexity of the logic inside your actions, you can get a big speedup. For example, on my welcome controller, index is action cached. Turning sessions off for this action, I see a &lt;em&gt;huge&lt;/em&gt; performance improvement on my windows development box:&lt;/p&gt;

&lt;pre&gt;
c1 real   c2 real  c1 r/s   c2 r/s  c1 ms/r  c2 ms/r  c1/c2
2.29700   0.27633   217.7   1809.4     4.59     0.55   8.31
2.45833   0.29200   203.4   1712.3     4.92     0.58   8.42
&lt;/pre&gt;


&lt;p&gt;This was measured against the default ActiveRecordStore session  implementation. But even with a faster session implementation, the difference is astonishing:&lt;/p&gt;

&lt;pre&gt;
c1 real   c2 real  c1 r/s   c2 r/s  c1 ms/r  c2 ms/r  c1/c2
1.20333   0.26600   415.5   1879.7     2.41     0.53   4.52
1.35933   0.27633   367.8   1809.4     2.72     0.55   4.92
&lt;/pre&gt;


&lt;p&gt;So it is certainly worthwhile  to consider turning sessions off for controllers that don't need them.&lt;/p&gt;
</description>
        <pubDate>2005-11-05T09:02:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/05/session-off</guid>
        <link>/blog/articles/2005/11/05/session-off</link>
      </item>
    
      <item>
        <title>Don't use Pstore as a session container</title>
        <description>&lt;p&gt;You really shouldn&amp;#8217;t be using Pstore for Rails. Apart from the fact that it doesn&amp;#8217;t scale to a setup with more than 1 box, it is much slower than using the database for session storage, for example.&lt;/p&gt;
&lt;p&gt;Using a &lt;a href=&quot;/blog/pages/pstore_nono.html&quot;&gt;Mysql session store&lt;/a&gt; can be up to 90% faster. Under, Linux, that is.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re on a Windows box, the difference can be staggering: &lt;a href=&quot;/blog/pages/pstore_nono_windows.html&quot;&gt;up to 560%!&lt;/a&gt;&lt;/p&gt;</description>
        <pubDate>2005-11-04T04:41:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/04/dont-use-pstore-as-a-session-container</guid>
        <link>/blog/articles/2005/11/04/dont-use-pstore-as-a-session-container</link>
      </item>
    
      <item>
        <title>Faster Pagination</title>
        <description>&lt;p&gt;Rails version 0.14 and upward contain a massive &lt;a href=&quot;http://dev.rubyonrails.org/ticket/1334&quot;&gt;performance improvement&lt;/a&gt; for &lt;a href=&quot;http://api.rubyonrails.com/classes/ActionView/Helpers/PaginationHelper.html&quot;&gt;pagination&lt;/a&gt;. Most of it is free and any app will benefit from it without even knowing.&lt;/p&gt;

&lt;p&gt;However, there's also a little api addition to the pagination helper module, which can be used to speed up your paginated pages even more, if necessary.&lt;/p&gt;

&lt;p&gt;We're talking about &lt;em&gt;pagination_links_each&lt;/em&gt;. It takes the same parameters as &lt;em&gt;pagination_links&lt;/em&gt; but instead of calling &lt;em&gt;link_to&lt;/em&gt; to create the html code for each link, it yields the page number to a block. It is the block's responsibility to create the html code for the link.&lt;/p&gt;

&lt;p&gt;So for example, you could write&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;pagination_links_each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:window_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;a href=&amp;#39;?page=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/a&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;instead of&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;pagination_links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:window_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The first version is faster than the second one, because it avoids creating lots of intermediate data structures to generate the html code. Additionally, the created html is shorter and less data gets transmitted over the wire. And the code will work for any page embedding it.&lt;/p&gt;

&lt;p&gt;The speedup obtained will of course depend on your app. Here's &lt;a href=&quot;/blog/pages/paginator_speedup.html&quot;&gt;some data&lt;/a&gt; for paginated pages of my application, showing speedups ranging from 11 to 26%. Quite an improvement for adding one line of code!&lt;/p&gt;
</description>
        <pubDate>2005-11-03T21:24:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/03/faster-pagination</guid>
        <link>/blog/articles/2005/11/03/faster-pagination</link>
      </item>
    
      <item>
        <title>Blog opened!</title>
        <description>&lt;p&gt;So finally I managed to get me a place in the blogosphere. Hey!&lt;/p&gt;
&lt;p&gt;The main purpose of this blog will be to keep a log of (my) activities related to improving performance of the &lt;a href=&quot;http://www.rubyonrails.org&quot;&gt;Rails&lt;/a&gt; web application framework.&lt;/p&gt;
&lt;p&gt;A good deal of work already went into performance improvement since realease 0.12.1. To sum it up: I managed to improve the throughput of a &lt;a href=&quot;/knzlpzl&quot;&gt;recipe database application&lt;/a&gt; by a &lt;strong&gt;factor of 4&lt;/strong&gt; since I started this work, going from around 50 requests per second to over 220 requests per seconds.&lt;/p&gt;
&lt;p&gt;In order to ease performance measurements of Rails applications, I have developed the package &lt;a href=&quot;http://railsbench.rubyforge.org&quot;&gt;railsbench&lt;/a&gt;. It really does make performance regression tests easy, so give it try!&lt;/p&gt;
&lt;p&gt;And stay tuned for further improvements :-)&lt;/p&gt;</description>
        <pubDate>2005-11-02T00:24:00+01:00</pubDate>
        <guid isPermaLink="false">/blog/articles/2005/11/02/blog-opened</guid>
        <link>/blog/articles/2005/11/02/blog-opened</link>
      </item>
    
  </channel>
</rss>

