<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>g's blog</title>
	
	<link>http://blogs.dwakn.com/g</link>
	<description />
	<lastBuildDate>Thu, 20 May 2010 20:21:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/GsBlog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="gsblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>8 requirements that good backup software needs to fulfil</title>
		<link>http://blogs.dwakn.com/g/2010/05/20/8-requirements-that-good-backup-software-needs-to-fulfil/</link>
		<comments>http://blogs.dwakn.com/g/2010/05/20/8-requirements-that-good-backup-software-needs-to-fulfil/#comments</comments>
		<pubDate>Thu, 20 May 2010 19:26:36 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=233</guid>
		<description><![CDATA[I’ve been thinking about backup solutions, and have been trying to find one that fits what I need. I have yet to find one, and this post is the first step in outlining what I need (and hopefully what other people need), with the end goal of building the perfect backup solution. (disclaimer: these are [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve been thinking about backup solutions, and have been trying to find one that fits what I need. I have yet to find one, and this post is the first step in outlining what I need (and hopefully what other people need), with the end goal of building the perfect backup solution.</p>
<p><span id="more-233"></span></p>
<p>(disclaimer: these are 8 requirements for me, yours may differ!)</p>
<p>Something to remember: <strong>When</strong> your hard drive dies, do you have your data safely stored somewhere else? A good test would be if all the hard drives in your pc all stopped working right now, would you lose any critical or valuable data? Do you have backups? Can you restore your backups? What about if your whole house burned down?</p>
<p>I’ve found that available backup software out there is either to complicated, doesn’t do what I want, or too expensive. I’ve listed out what I feel are <strong>my</strong> requirements for backup software (which means that they’re probably not your requirements!). Note that since my primary machine is running Windows, I’m looking at requirements that Windows supports.</p>
<p>I don’t need a full disk backup, rather on a file-by-file basis. <strong>When</strong> my drive crashes, I’d probably want to use the opportunity to re-install my operating system anyway.</p>
<h3>1. Simple and easy to use</h3>
<p>Obviously all software should be easy to use, but why are a lot of backup solutions so complex? Ask me what to backup, where to store the backup and how often to run. Otherwise, leave me alone (obviously if there is a problem, let me know!).</p>
<h3>2. Simple backup format</h3>
<p>I should be able to open windows explorer, and view the files in a backup set without having to run any special software. This also helps with the first requirement – if your files are stored as files on the drive, anything <em>should</em> be able to read them. When you lose your main drive, it makes it easier if you can plug in your backup drive, and just copy files off it.</p>
<h3>3. Actually backup (and restore!) your files</h3>
<p>This seems obvious, but I’ve seen backup solutions that will silently backup all your files, but then barf when asked to restore them (looking at you, Windows Backup). The only way to be sure is to try restore your data at regular intervals, no matter which system you use. If the storage format is simple, as above, this is less of an issue, but you should still test it on a regular basis!</p>
<h3>4. Stay out of my way</h3>
<p>You should not have to remember to run a backup. Backup software should run automatically, and quietly in the background. Once you’ve scheduled it, it should do the rest. Disconnecting an external drive half way through a backup should not cause any problems when you plug the drive in again – it should carry on, ideally where it left off.</p>
<h3>5. Handle multiple destinations</h3>
<p>I would like to backup to external hard drives, USB flash drives and network computers. The software should automatically handle things like drive letter changes for external USB drives.</p>
<p>I want to define a set of files to backup, then point the software at multiple places. When plugging in a USB drive, the software should automatically kick off a backup if one is scheduled. When connecting to a network, if the destination machine is available, start the backup.</p>
<h3>6. Keep history</h3>
<p>Being able to go back a couple of months and retrieve a file from then is very handy. The software should do intelligent diffing as well as cleanup of old backup sets. If I’ve changed one 1MB file within of a couple of hundred gigabytes of files, I don’t expect the next backup to take much more than 1MB of extra space.</p>
<h3>7. Offline</h3>
<p>I have too much data to realistically store online. Living in South Africa exacerbates it because we have such constrained bandwidth availability (e.g. ADSL with 3GB limit). An online backup solution, while nice, is not really an option for most South Africans. If you have a couple of megabytes of word docs, then by all means install something like <a href="http://www.dropbox.com/">Dropbox</a> or <a href="http://www.sugarsync.com/">SugarSync</a> and be done.</p>
<h3>8. Quick</h3>
<p>Obviously there is a limit to how quick backup software can be – it still needs to enumerate over all files you’re choosing to backup, but a backup of a couple of hundred changed files (from a typical day of work) should take under 5 minutes to complete.</p>
<h3>Other nice-to-have features</h3>
<p>While these would be nice, they are not critical for me at the moment.</p>
<p><strong>Encryption:</strong> Encrypting your files would be nice, but this would break the “Simple format” requirement above. Maybe have an external usb drive encrypted using <a href="http://www.truecrypt.org/">TrueCrypt</a>?</p>
<p><strong>Handle locked files:</strong> Files that are in use should also be backed up. This would involve using Volume Shadow Copy.</p>
<p>Primarily, a backup solution needs to be simple, just work and stay out of my way. Anything I’ve left out?</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2010/05/20/8-requirements-that-good-backup-software-needs-to-fulfil/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wallpaper goodness</title>
		<link>http://blogs.dwakn.com/g/2010/02/15/wallpaper-goodness/</link>
		<comments>http://blogs.dwakn.com/g/2010/02/15/wallpaper-goodness/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 08:00:44 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=220</guid>
		<description><![CDATA[Quick note, I&#8217;ve uploaded some hi-res wallpapers on my photoblog site. Right, back to work.]]></description>
			<content:encoded><![CDATA[<p><a href="http://refracted.co.za/wallpapers/"><img class="alignright size-thumbnail wp-image-222" title="Wallpaper: Cascade" src="http://blogs.dwakn.com/g/wp-content/uploads/2010/02/cascade_300x200-150x100.jpg"  alt="" width="150" height="100" / rel="lightbox[roadtrip]"></a>Quick note, I&#8217;ve uploaded some <a href="http://refracted.co.za/wallpapers/">hi-res wallpapers</a> on <a href="http://refracted.co.za/">my photoblog site</a>.</p>
<p>Right, back to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2010/02/15/wallpaper-goodness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On Mono</title>
		<link>http://blogs.dwakn.com/g/2009/09/07/on-mono/</link>
		<comments>http://blogs.dwakn.com/g/2009/09/07/on-mono/#comments</comments>
		<pubDate>Mon, 07 Sep 2009 06:47:50 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[microsoft net framework]]></category>
		<category><![CDATA[mono]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=214</guid>
		<description><![CDATA[So, I’ve been playing around with Mono on a virtual machine for a while now, and want to just put down some thoughts. Note that this won’t be an in-depth review of Mono, but just my initial experiences coming from a MS .net background. (for those of you that don’t know, Mono is an open-source [...]]]></description>
			<content:encoded><![CDATA[<p>So, I’ve been playing around with <a href="http://www.mono-project.com/">Mono</a> on a virtual machine for a while now, and want to just put down some thoughts. Note that this won’t be an in-depth review of Mono, but just my initial experiences coming from a MS .net background.</p>
<p>(for those of you that don’t know, Mono is an open-source implementation of the .net CLR. <a href="http://www.mono-project.com/What_is_Mono">Go here for more details</a>. It is actually quite a bit more than that, but coming from using .net, that is the part the interests me – at least at the moment.)</p>
<p>Firstly, one of the interesting things about Mono, is that you can take an assembly compiled using Microsoft&#8217;s tools, and run it under Mono, <em>without any changes</em>. Obviously, if you’re talking to the windows registry or using MS specific p-invoke calls, it wont work, but if your code is 100% managed, the chance that it will just work is pretty high.</p>
<h3>Tooling</h3>
<p>In terms of actually developing directly on Linux and using the Mono tools (rather than the Microsoft ones), there is an IDE called <a href="http://monodevelop.com/">MonoDevelop</a> that comes very close to the functionality of Visual Studio – in places its better (it can even open and save Visual Studio solutions and projects).</p>
<p>All the other usual command line tools are there, most importantly, there is a MSBuild clone called x-build, which lets you use your existing build scripts.</p>
<p>And something that is important for me, <a href="http://nunit.org/">NUnit</a> runs fine on mono.</p>
<p>For porting existing projects to Mono, there is a tool, called <a href="http://mono-project.com/MoMA">MoMA</a>, which scans your source code, flagging any areas it identifies as being a potential problem.</p>
<h3>Benefits</h3>
<p>The most obvious one is that of licensing. Since Mono is open-source, and runs on an open-source operating system, there are zero licensing costs. This is attractive if you’re wanting to have multiple servers running your application. Windows licenses for 20 servers is a non-trivial cost.</p>
<p>Mono is also cross-platform. It runs in environments and on devices where you won’t find the Microsoft .net framework. Taken from the mono site:</p>
<blockquote><p>Mono is built to be cross platform. Mono runs on <a href="http://www.mono-project.com/Mono:Linux">Linux</a>, <a href="http://www.mono-project.com/Mono:Windows">Microsoft Windows</a>, <a href="http://www.mono-project.com/Mono:OSX">Mac OS X</a>, <a href="http://www.mono-project.com/Mono:BSD">BSD</a>, and <a href="http://www.mono-project.com/Mono:Solaris">Sun Solaris</a>, <a href="http://www.mono-project.com/Mono:Wii">Nintendo Wii</a>, <a href="http://www.mono-project.com/Mono:PlayStation3">Sony PlayStation 3</a>, <a href="http://www.mono-project.com/Mono:Iphone">Apple iPhone</a>. It also runs on <a href="http://www.mono-project.com/Mono:X86">x86</a>, <a href="http://www.mono-project.com/Mono:AMD64">x86-64</a>, <a href="http://www.mono-project.com/Mono:IA64">IA64</a>, <a href="http://www.mono-project.com/Mono:PowerPC">PowerPC</a>, <a href="http://www.mono-project.com/Mono:SPARC">SPARC (32)</a>, <a href="http://www.mono-project.com/Mono:ARM">ARM</a>, <a href="http://www.mono-project.com/index.php?title=Mono:Alpha&amp;action=edit">Alpha</a>, <a href="http://www.mono-project.com/Mono:S390">s390, s390x (32 and 64 bits)</a> and more. Developing your application with Mono allows you to run on nearly any computer in existence.</p></blockquote>
<h3>Distribution</h3>
<p>I’m not sure about older versions, but the latest version of <a href="http://www.ubuntu.com/">Ubuntu</a> has Mono installed already. A couple of the pre-installed applications are written in C#.</p>
<p>To be honest, I’ve only used Mono under Ubuntu, so cannot comment on its availability in other distributions, but the Mono website <a href="http://www.go-mono.com/mono-downloads/download.html">recommends</a> <a href="http://www.opensuse.org/">openSUSE</a>.</p>
<h3>Conclusion</h3>
<p>So, in conclusion, I’m very impressed, well done guys. I’ve not yet had time to take one of our larger projects and get it running on Mono, but that&#8217;s the next step.</p>
<p>This is more a note to myself, but below is a list of things I want to investigate further around Mono:</p>
<ul>
<li>Ease of porting a largish existing application to Mono</li>
<li>Do common frameworks run on Mono? (things like <a href="http://www.asp.net/mvc/">ASP.NET MVC,</a> <a href="http://nhforge.org/">NHibernate</a>, <a href="http://www.castleproject.org/container/index.html">Castle Windsor</a> etc)</li>
<li>Windows Forms support (this was spotty when I looked at it a couple of years ago – its meant to be better)</li>
<li>Performance vs the Microsoft stack</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/09/07/on-mono/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MSI version matching upgrade woes</title>
		<link>http://blogs.dwakn.com/g/2009/07/08/msi-version-matching-upgrade-woes/</link>
		<comments>http://blogs.dwakn.com/g/2009/07/08/msi-version-matching-upgrade-woes/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 12:49:15 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=200</guid>
		<description><![CDATA[We&#8217;re distributing our .net application using Microsoft&#8217;s MSI installer technology (using the very powerful WiX to do it). We&#8217;ve recently seen a problem with the installer not upgrading older versions, but rather just installing on top of the existing version, which results in the application being listed twice in the &#8220;Add/remove programs&#8221; (Programs and Features [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re distributing our .net application using Microsoft&#8217;s MSI installer technology (using the very powerful <a href="http://wix.sourceforge.net/">WiX</a> to do it).</p>
<p>We&#8217;ve recently seen a problem with the installer not upgrading older versions, but rather just installing on top of the existing version, which results in the application being listed twice in the &#8220;Add/remove programs&#8221; (Programs and Features in Vista) section, one for each version. This results in weird things happening, like uninstalling one of them leaves the other one still installed with all the application files removed.</p>
<p>I ensured that we kept the same upgrade guid, with the version number incrementing, but all looked good. After searching and trying different things, I finally found <a href="http://msdn.microsoft.com/en-us/library/aa372379%28VS.85%29.aspx">this gem</a>, hidden away in the MS documentation:</p>
<blockquote><p>Note that Windows Installer uses only the first three fields of the product version. If you include a fourth field in your product version, the installer ignores the fourth field.</p></blockquote>
<p>Why?!??</p>
<p>Our version numbers are in the order of 3.2.0.1234, 3.2.0.1456 (where the 4th number increments based on the Subversion revision number). The installer was seeing the version numbers as 3.2.0, i.e. the same, and not uninstalling the old version. Changing the installer version number to 3.2.1234 fixes this.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/07/08/msi-version-matching-upgrade-woes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WP Super Cache not caching (solution)</title>
		<link>http://blogs.dwakn.com/g/2009/07/01/wp-super-cache-not-caching-solution/</link>
		<comments>http://blogs.dwakn.com/g/2009/07/01/wp-super-cache-not-caching-solution/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 08:53:44 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[Dwakn]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[output buffer]]></category>
		<category><![CDATA[plug ins]]></category>
		<category><![CDATA[wpsupercache]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=190</guid>
		<description><![CDATA[(this post is more a note to my future self than anything else) The WP Super Cache plugin for WordPress is a pretty awesome plugin. The other day I was having problems with it not doing any caching and spitting out the following just before the head tag (where the wp_head() call is): &#60;!-- Page [...]]]></description>
			<content:encoded><![CDATA[<p>(this post is more a note to my future self than anything else)</p>
<p>The WP Super Cache plugin for WordPress is a pretty awesome plugin. The other day I was having problems with it not doing any caching and spitting out the following just <em>before</em> the head tag (where the wp_head() call is):</p>
<pre>&lt;!-- Page not cached by WP Super Cache. No closing HTML tag. Check your theme. --&gt;</pre>
<p>This was very odd. Everything I could find on the web regarding this problem was seeing this tag <em>at the end</em> of the html. Eventually I found a post that sounded similar to mine (and of course now I cannot find it again, unfortunately). It mentioned a plug-in using output buffering incorrectly. This makes sense, as looking in the source code of WP Super Cache, it outputs the message above in its output buffer handler if it cannot find a &lt;/html&gt; closing tag. Needless to say, after a couple of hours fiddling, it turns out that  it was a plug-in that <em>I</em> had written especially for the site, and it was doing exactly what the post mentioned (i.e. it was calling <em>ob_end_flush()</em> without calling <em>ob_start()</em>).</p>
<p>So it was all my fault, and I&#8217;ll probably do it in the future, hence this post!</p>
<p>So, note to self: If you see this in the future, check the plug-ins.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/07/01/wp-super-cache-not-caching-solution/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Don’t use @@IDENTITY</title>
		<link>http://blogs.dwakn.com/g/2009/05/26/dont-use-identity/</link>
		<comments>http://blogs.dwakn.com/g/2009/05/26/dont-use-identity/#comments</comments>
		<pubDate>Tue, 26 May 2009 14:23:55 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[identity]]></category>
		<category><![CDATA[sqlserver]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/2009/05/26/dont-use-identity/</guid>
		<description><![CDATA[If you’re using SQL Server, and you’re inserting records into a table with an auto increment primary key, I suggest you don’t use @@IDENTITY to retrieve the previously inserted Id. Rather use SCOPE_IDENTITY(). The reason for this is that @@IDENTITY gives you the last generated Id in the current session vs. SCOPE_IDENTITY() gives you the [...]]]></description>
			<content:encoded><![CDATA[<p>If you’re using SQL Server, and you’re inserting records into a table with an auto increment primary key, I suggest you don’t use @@IDENTITY to retrieve the previously inserted Id. Rather use SCOPE_IDENTITY().</p>
<p>The reason for this is that @@IDENTITY gives you the last generated Id in the <em>current session</em> vs. SCOPE_IDENTITY() gives you the last generated Id in the <em>current scope</em>.</p>
<p>The current session includes any triggers that run on the table after the insert. The current scope is just the current stored procedure that you’re in.</p>
<p>We were bitten by this recently. We were using @@IDENTITY when inserted into a table that is replicated. Upon insert the replication trigger was firing, inserting a record somewhere else. @@IDENTITY was giving us the identity of the record the trigger inserted.</p>
<p>Changing the @@IDENTITY to SCOPE_IDENTITY() fixed the problem.</p>
<p>This was even nastier in that by total fluke, the identity was matching a record that already existed, so when we used the retrieved identity to insert into another table, we didn’t violate the foreign key constraint.</p>
<p>Lesson learnt!</p>
<p><strong>Update: I&#8217;ve found a page with an <a href="http://www.sqlteam.com/article/alternatives-to-identity-in-sql-server-2000">in-depth look at the different techniques</a>. Its for SQL Server 2000, but applies to 2005/2008 too.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/05/26/dont-use-identity/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google and search ranking</title>
		<link>http://blogs.dwakn.com/g/2009/05/04/google-and-search-ranking/</link>
		<comments>http://blogs.dwakn.com/g/2009/05/04/google-and-search-ranking/#comments</comments>
		<pubDate>Mon, 04 May 2009 07:06:53 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[Dwakn]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[website]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=178</guid>
		<description><![CDATA[I&#8217;ve recently finished a new site for a client, and in the process of developing, I uploaded a test site to a web server for the client to review. Since going live with the actual site, I left the test site up and running (in the assumption that its less effort to leave it up [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently finished a new site for a client, and in the process of developing, I uploaded a test site to a web server for the client to review. Since going live with the actual site, I left the test site up and running (in the assumption that its less effort to leave it up than to take it down).</p>
<p>Unfortunately, google managed to find the test site and ranked it higher than the proper site for a couple of the keywords. Not good! Its a simple fix to put in a mod_rewrite redirect rule, but its quite incredible how quickly google managed to find a site that has no incoming links.</p>
<p>I have a feeling that its related to the site map plugin that we&#8217;re using for wordpress, I think that it pinged google when we were developing the site, and google happily went along and indexed the site.</p>
<p>So, if you&#8217;re developing a site, and put up a test version, make sure that you either take it down when making the site live, or ensure that it redirects to the correct site.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/05/04/google-and-search-ranking/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Compact 3.5 Performance and NHibernate</title>
		<link>http://blogs.dwakn.com/g/2009/04/07/sql-compact-35-performance-and-nhibernate/</link>
		<comments>http://blogs.dwakn.com/g/2009/04/07/sql-compact-35-performance-and-nhibernate/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 12:13:04 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=165</guid>
		<description><![CDATA[We&#8217;re using SQL Compact 3.5 in a smart client desktop application, talking to it with NHibernate and are experiencing performance problems in a couple of places. In general, we&#8217;re very happy with the database, it is most of the time pretty fast, and easy to work with. The fact that it runs within our process [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re using SQL Compact 3.5 in a smart client desktop application, talking to it with NHibernate and are experiencing performance problems in a couple of places.</p>
<p>In general, we&#8217;re very happy with the database, it is most of the time pretty fast, and easy to work with. The fact that it runs within our process also helps, as its easy to install and use. This is especially useful, as we are going to be running on relatively low-spec machines (laptops with 500MB ram).</p>
<p>We are however seeing a performance problem in SELECT statements with multiple joins (&gt; 5).</p>
<p><span id="more-165"></span></p>
<p><a href="http://msdn.microsoft.com/en-us/library/ms172432.aspx">This article</a> warns:</p>
<blockquote><p>In general, if a significant number of your queries require joins of more than five or six tables, you should consider denormalization.</p></blockquote>
<p>We are seeing queries that take around 4 minutes, whereas running the same query on a proper sql server takes less than a second.</p>
<p>When dumping out the query plans, and reviewing it, we are seeing in most cases, a full table scan taking place, and joining of all rows before filtering. Running the same query on the full sql server (with the same schema), it uses the indexes, and filters as expected. I’m going to demonstrate this issue, and a possible solution to the problem (tests were done using SQL Compact 3.5 SP1).</p>
<p>I’ve created a simple schema, as defined in the diagram below (should be pretty familiar):</p>
<p><img style="display: block; float: none; margin-left: auto; margin-right: auto" title="table diagram" src="http://blogs.dwakn.com/g/wp-content/uploads/2009/04/image.png" alt="table diagram" width="310" height="414" /></p>
<p>(all tables had 1000 records in them, with the exception of the order_line table, which had ~16 000 records)</p>
<p>I’m going to use the following query, which is a bit contrived, but it is complex enough to display the issue:</p>
<pre class="brush: sql;">SELECT   product.name,
         COUNT([order].id) AS order_count
FROM     order_line
         LEFT OUTER JOIN [order]
           ON [order].id = order_line.order_id
         LEFT OUTER JOIN product
           ON product.id = order_line.product_id
WHERE    [order].id IN ('{list of ~100 integers}')
         AND product.quantity_in_stock &lt; order_line.quantity
GROUP BY product.name
ORDER BY order_count DESC,
         product.name</pre>
<p>In SQL Compact, this generates the following query plan (click the image for the full size):</p>
<p><a href="http://blogs.dwakn.com/g/wp-content/uploads/2009/04/image5.png"  rel="lightbox[roadtrip]"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="query plan" src="http://blogs.dwakn.com/g/wp-content/uploads/2009/04/image-thumb4.png" border="0" alt="query plan" width="440" height="98" /></a></p>
<p>On the right of the query plan, you can see it joining the order and order_line tables (takes ~97% of the time). The problem is that it does this join <em>before</em> it filters out the orders, thereby reading all the records in the order_line table (which is obviously big!). This query runes noticeably slower with more data. Running the query on the full SQL Server results in it using the indexes as expected.</p>
<p>The solution to this, is to manually optimize the query yourself, instead of relying on the database engine to do it for you, by removing the LEFT JOINs and inverting the query, using INNER JOINs rather, to force the engine to filter rows out as early as possible (you’d usually write the query like this anyway, if you were doing it by hand, but remember, we’re using NHibernate to generate the query).</p>
<p>Here is the above query, optimized:</p>
<pre class="brush: sql;">SELECT   product.name,
         COUNT([order].id) AS order_count
FROM     [order]
         INNER JOIN order_line
           ON order_line.order_id = [order].id
         INNER JOIN product
           ON product.id = order_line.product_id
WHERE    [order].id IN ('{list of ~100 integers}')
         AND product.quantity_in_stock &lt; order_line.quantity
GROUP BY product.name
ORDER BY order_count DESC,
         product.name</pre>
<p>and the corresponding query plan:</p>
<p><a href="http://blogs.dwakn.com/g/wp-content/uploads/2009/04/image6.png"  rel="lightbox[roadtrip]"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="optimized query plan" src="http://blogs.dwakn.com/g/wp-content/uploads/2009/04/image-thumb5.png" border="0" alt="optimized query plan" width="440" height="93" /></a></p>
<p>If you examine the query plan, you’ll notice that it’s filtering the rows up front, rather than joining and then filtering.</p>
<p>So, in conclusion, it doesn’t seem that SQL Compact optimizes LEFT JOINs properly, and you have to optimize the query yourself to avoid table scans and poor performance.</p>
<p>One important fact to note is that we’re using NHibernate to perform the querying, and its generating sql with lots of LEFT JOINs in it (nothing wrong with that, most databases optimize this quite well). The number of joins are determined by what base object you choose to query on, and how many values from other objects you’re pulling back.</p>
<p>We’ve since replaced the generated queries that show this performance problem with hard-coded named queries, written with inner joins as described above.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/04/07/sql-compact-35-performance-and-nhibernate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Empty unit tests</title>
		<link>http://blogs.dwakn.com/g/2009/03/10/empty-unit-tests/</link>
		<comments>http://blogs.dwakn.com/g/2009/03/10/empty-unit-tests/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 13:51:26 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/2009/03/10/empty-unit-tests/</guid>
		<description><![CDATA[I was reviewing some code, and noticed a couple of unit tests that had “TODO” comments in them (and no code). The problem is that when running these tests, they were passing. Someone reading the list of tests would assume that the test was testing what it claimed to be testing, when in actual fact [...]]]></description>
			<content:encoded><![CDATA[<p>I was reviewing some code, and noticed a couple of unit tests that had “TODO” comments in them (and no code). The problem is that when running these tests, they were passing. Someone reading the list of tests would assume that the test was testing what it claimed to be testing, when in actual fact its doing nothing.</p>
<p>The first option to avoid this problem is to not actually create test methods until you’re ready to implement them. </p>
<p>I know I like to sometimes lay out a list of tests I want to implement before actually writing them. If you want to do this, then I suggest you create the methods, but ensure that the test is ignored (in nUnit, put an [Ignore] attribute onto the method), or that it fails (in nUnit, Assert.Fail). This is especially important if you’re going to commit to your source control system your partially complete tests.</p>
<p>Doing it this way will ensure that </p>
<ol>
<li>You don’t forget that you need to implement the test.</li>
<li>That someone doesn’t think that something is being tested when in actual fact it isn’t.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/03/10/empty-unit-tests/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Yahoo Pipes to aggregate feeds</title>
		<link>http://blogs.dwakn.com/g/2009/03/10/using-yahoo-pipes-to-aggregate-feeds/</link>
		<comments>http://blogs.dwakn.com/g/2009/03/10/using-yahoo-pipes-to-aggregate-feeds/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 09:46:30 +0000</pubDate>
		<dc:creator>Gareth</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blogs.dwakn.com/g/?p=138</guid>
		<description><![CDATA[I’ve got a list of links in the sidebar of this blog. What is not obvious is that this list is an aggregated list of links that come from multiple sources. At the moment, I mark links as interesting from two sources: Delicious Google Reader (shared items) Ideally, I don’t want to have 2 lists [...]]]></description>
			<content:encoded><![CDATA[<p><img style="border: 0pt none !important; display: inline;" title="pipe" src="http://blogs.dwakn.com/g/wp-content/uploads/2009/03/pipe-thumb.png" border="0" alt="pipe" width="160" height="160" align="right" /> I’ve got a list of links in the sidebar of this blog. What is not obvious is that this list is an aggregated list of links that come from multiple sources. At the moment, I mark links as interesting from two sources:</p>
<ul>
<li><a href="http://delicious/gareth">Delicious</a></li>
<li><a href="http://www.google.com/reader/shared/07831905801884749627">Google Reader (shared items)</a></li>
</ul>
<p>Ideally, I don’t want to have 2 lists on the side, especially when most items I both bookmark in Delicious and share in Google Reader.</p>
<p>Enter Yahoo Pipes. Its an incredibly easy-to-use and powerful tool. You can see the pipe I’ve created here: <a title="http://pipes.yahoo.com/pipes/pipe.info?_id=wAcslJ753RGkTFabBR50VA" href="http://pipes.yahoo.com/pipes/pipe.info?_id=wAcslJ753RGkTFabBR50VA">http://pipes.yahoo.com/pipes/pipe.info?_id=wAcslJ753RGkTFabBR50VA</a>. If you click the “View&#8221; Source” link you can see how its put together.</p>
<p>The general idea is to:</p>
<ol>
<li>add multiple sources (fetch feed)</li>
<li>union them together into one feed</li>
<li>Ensure they are unique, based on the id</li>
<li>Sort them by the publish date</li>
<li>Output the result</li>
</ol>
<p>The end result is one rss feed that contains the unique list of links and is sorted properly. I just then point the WordPress RSS widget at that feed, and it works.</p>
<p>You can do a lot more fancy things, but what I’ve described above is the simplest.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.dwakn.com/g/2009/03/10/using-yahoo-pipes-to-aggregate-feeds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 1.376 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-08-04 09:04:26 -->
