<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Technical Notes &#187; query</title>
	<atom:link href="http://blog.anthonychaves.net/tag/query/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.anthonychaves.net</link>
	<description>Life is software and jujitsu</description>
	<lastBuildDate>Tue, 16 Feb 2010 22:15:16 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The Evil Query</title>
		<link>http://blog.anthonychaves.net/2008/03/18/the-evil-query/</link>
		<comments>http://blog.anthonychaves.net/2008/03/18/the-evil-query/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 16:21:47 +0000</pubDate>
		<dc:creator>Anthony Chaves</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[scalability]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[criteria]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[query]]></category>

		<guid isPermaLink="false">http://blog.anthonychaves.net/java/2008/03/18/the-evil-query</guid>
		<description><![CDATA[Here is the use case: I want to search all of my bookmarks by multiple tags with an &#8220;and&#8221; operation.  That means I want to see bookmarks that are tagged with Java AND JavaEE, not just Java and not just JavaEE.  I want to see bookmarks tagged with C# AND 3.5 not just [...]]]></description>
			<content:encoded><![CDATA[<p>Here is the use case: I want to search all of my bookmarks by multiple tags with an &#8220;and&#8221; operation.  That means I want to see bookmarks that are tagged with Java AND JavaEE, not just Java and not just JavaEE.  I want to see bookmarks tagged with C# AND 3.5 not just C# and not just 3.5.  For most of the project I&#8217;m using Hibernate and the Criteria API with a lot of success.  In this case I was not able to massage Hibernate into creating the correct query and that&#8217;s fine.  Hibernate has its uses and it is acceptable to write custom SQL when the need arises.  I wrote a method to build up the query and execute it.  Here is part of the method that builds up the query:</p>
<table bgcolor="#ffffff" border="0" cellpadding="3" cellspacing="0">
<tr>
<td align="left" nowrap="nowrap" valign="top"><code><font color="#000000">StringBuilder sqlString =<br />
</font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong>new </strong></font><font color="#000000">StringBuilder</font><font color="#000000">(<br />
</font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#2a00ff">                                "select distinct(b.id)<br />
</font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#2a00ff">from bookmarks b "</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>int </strong></font><font color="#000000">counter = </font><font color="#990000">0</font><font color="#000000">;</font><br />
<font color="#ffffff">    </font><font color="#7f0055"><strong>for</strong></font><font color="#000000">(</font><font color="#000000">Tag tag : tags</font><font color="#000000">) {</font><br />
<font color="#ffffff">      </font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#000000">String alias = </font><font color="#2a00ff">"j" </font><font color="#000000">+ Integer.toString</font><font color="#000000">(</font><font color="#000000">counter</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#000000">String joinFragment = </font><font color="#2a00ff">" inner join bookmarks_to_tags {alias}<br />
</font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#2a00ff"> on b.id = {alias}.bookmark_id<br />
</font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#2a00ff"> and {alias}.tag_id = ? "</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#000000">joinFragment = joinFragment.replace</font><font color="#000000">(</font><font color="#2a00ff">"{alias}"</font><font color="#000000">, alias</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#000000">sqlString.append</font><font color="#000000">(</font><font color="#000000">joinFragment</font><font color="#000000">)</font><font color="#000000">;</font><br />
<font color="#ffffff">      </font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#7f0055"><strong> </strong></font></code><code><font color="#000000">counter++;</font><br />
<font color="#ffffff">    </font><font color="#000000">}</font></code></td>
</tr>
</table>
<p>Right away it looks like this query will get very expensive for large tag sets.  For smaller sets the query performs in a reasonable amount of time but more than 12 tags makes the query take quite a while.  This is exacerbated by the fact that this query will be executed multiple times if there is a sufficiently large result set (default is over 25) to give the user a paginated view.  This totally flies in the face of being nice to the database.  Hammering it with a complex query over and over won&#8217;t do the users any favors.</p>
<p>What are my options here?  I can work on making this query less complex (something that I will certainly do), but there is still the problem that, no matter how nice this query becomes, the query will be executed over and over as a user pages through the results.  The complexity of the query and its repeated execution makes the result set a good candidate for caching.  Caching the result set in memory with a key tied to the user or their session will allow the expensive query to be executed once with the bookmarks stored in a cache.  When the user pages through the results the cache will be consulted first where the result set will be stored.  I&#8217;m in the process of selecting a caching package for this project so I will post my selection and integration process soon.</p>
<p>Until then, I&#8217;d be happy to hear any suggestions on making this query a little nicer while preserving its &#8220;andness&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonychaves.net/2008/03/18/the-evil-query/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
