<?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>techfounder &#187; Open Source</title>
	<atom:link href="http://www.techfounder.net/category/os/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.techfounder.net</link>
	<description>Blog about web development and Internet entrepreneurship</description>
	<lastBuildDate>Mon, 22 Aug 2011 08:36:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Zend Framework dependency manager</title>
		<link>http://www.techfounder.net/2010/11/02/zend-framework-dependency-manager/</link>
		<comments>http://www.techfounder.net/2010/11/02/zend-framework-dependency-manager/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 13:38:20 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=571</guid>
		<description><![CDATA[Reusing Zend Framework based code can be a bit of a pain - you do not want to include the entire framework just for a few classes, yet tracking down the dependencies needed to run your code can be time consuming and it's hard to tell if you aren't missing anything. To overcome those issues, [...]]]></description>
			<content:encoded><![CDATA[<p>Reusing Zend Framework based code can be a bit of a pain - you do not want to include the entire framework just for a few classes, yet tracking down the dependencies needed to run your code can be time consuming and it's hard to tell if you aren't missing anything.</p>
<p>To overcome those issues, I wrote a utility class to automatically resolve Zend Framework dependencies by fetching them from the online SVN repository when they are needed (and then storing them locally). The class is available for download from <a title="Download Zend Framework dependency manager" href="http://www.binpress.com/app/zf-dependency-manager/30">Binpress</a> under the <a title="MIT open-source license" href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</p>
<p><span id="more-571"></span></p>
<p><strong>How does it work:</strong></p>
<ul>
<li>An autoload function is prepended to the spl autoload stack</li>
<li>The auotload function catches requests for Zend Framework classes</li>
<li>If the class is not available locally, the dependency manager downloads it from the SVN repository</li>
<li>If the class has additional dependencies handled by internal class managers in the ZF (such as plugins and helpers), those are fetched as well</li>
<li>All fetched class files are stored locally in a predefined location (such as /library/Zend as is the norm)</li>
<li>The class is then loaded</li>
</ul>
<p><strong>Usage:</strong></p>
<ul>
<li>Include the Zdm class (Zdm.php) at the beginning of the application (in the bootstrap, if you are using one)</li>
<li>Run the static start() function</li>
<li>The start() function accepts several optional parameters
<ul>
<li>'libraryPath' - The local path to store fetched ZF classes. The default is the same directory as the Zdm class file (expecting it to be under /library)</li>
<li>'zfVersion' - The Zend Framework version to fetch. Default is 1.10.8</li>
<li>'prependStack' - By default the autoload function is prepended to the stack. If this interferes with any existing autoload functions, you can set this value to false and it will be appended to the stack instead.</li>
<li>'repository' - Change the location of the repository to fetch ZF classes from. You can set this value to a local installation of the framework for better performance.</li>
</ul>
</li>
<li>The first time the application is run with the dependency manager, it might take some  time to download all the dependencies. To avoid the script timing out, you should set the time limit to '0' using set_time_limit()</li>
</ul>
<p><strong>Notes</strong> - you need to remove 'require' and 'require_once' statements that load Zend Framework classes. Those statements produce a fatal error when the file is not found and cannot be trapped by the autoload function. I tried to recover from the warning sent before the fatal error, however it could not prevent the fatal error from happening.</p>
<p>This class can be used to minimize the needed framework build for current projects as well. Rename your Zend Framework library directory, and allow the dependency manager to build the library from classes that are actually used in the application. This usually results in a much smaller framework footprint. I've successfully used this class in several active projects to recreate the needed framework library that runs the entire application.</p>
<p>It is likely there are some dependencies that are not mapped yet in the class. If you encounter such dependencies, please let me so I could add it to the class.</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=571" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Zend Framework dependency manager" data-url="http://www.techfounder.net/2010/11/02/zend-framework-dependency-manager/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2010/11/02/zend-framework-dependency-manager/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Software licenses for dummies</title>
		<link>http://www.techfounder.net/2010/10/05/software-licenses-for-dummies/</link>
		<comments>http://www.techfounder.net/2010/10/05/software-licenses-for-dummies/#comments</comments>
		<pubDate>Tue, 05 Oct 2010 12:40:39 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Business Development]]></category>
		<category><![CDATA[Lionite]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=538</guid>
		<description><![CDATA[The legal aspects of selling software are, for the most part, pretty vague for most developers. During preparations for launching our software market, Binpress, I absorbed a lot of information from our very good copyright  attorney and got to understand much better the nuances of software licensing. Here are some of the lessons I learned. [...]]]></description>
			<content:encoded><![CDATA[<p>The legal aspects of selling software are, for the most part, pretty vague for most developers. During preparations for launching our <a title="binpress - web application component store" href="http://binpress.com">software market</a>, Binpress, I absorbed a lot of information from our <a href="http://2jk.org/english/">very good copyright  attorney</a> and got to understand much better the nuances of software licensing. Here are some of the lessons I learned.</p>
<p><span id="more-538"></span></p>
<h2>You need a software license when you are selling software</h2>
<p>Seems obvious, right? however, many freelance developers do not use any license. Common misconception seems to be that when you develop custom code for a client, he basically owns the code when the job is done. <strong>That premise is usually false</strong>. While the license given to custom software solutions is usually liberal, allowing changes to source-code (with conditions) - there are many restrictions that apply on the buyer. For example, it's very rare to allow a client to resell your work as his - though without a license, he can certainly do that.</p>
<p>The purpose of a license is to protect your intellectual property (IP) and copyright. While you may intend to allow a client to modify the source code you provide to fit his needs, it does not necessarily mean he can sell it or include it in his other works.</p>
<p>Lets go over some decisions you have to make when writing a software license and explain the legal terms that describe it:</p>
<h3>Do you want to allow clients to redistribute your software?</h3>
<p>The most basic and critical question. If you answer <strong>YES</strong>, the license is called a <strong>Sublicensable</strong> license and it allows license holders (your clients) to resell your code with their own license, as long as that license does not contradict your original license.</p>
<p>Sometimes, an additional condition is added that the software cannot be sold <em>as is</em> and must be included in a greater work to be sublicensed. This condition prevents your client from becoming your competitor and basically selling the same product you are selling. A sublicesnable license should be used when you want to allow clients to sell solutions based on your work - for example, the client wants to sell CMS product that uses a plug-in developed by you.</p>
<p>The opposite of a sublicesnable license is a <strong>Personal</strong> license. A personal license prohibits license holders from reselling, renting or even allowing use of your code by 3rd parties. This type of license is common when you are selling premade (non-custom) code and want to limit use to the client only. The vast majority of desktop applications are sold under this license.</p>
<h3>Do you want to allow clients to modify the source code?</h3>
<p>Despite what it may seem, a sublicensable license by itself does not allow clients to modify your code. In order to allow that, the license must include <strong>the right to create derivative works</strong>. A derivative work is a modified version of your source code.</p>
<p>Having the right to create derivative works in a sublicensable license by itself does not give the client the right to sell modifications (only the original code). In order to allow the sale of a modified version of your source code (either as standalone or as a part of a larger work), the license must include <strong>the</strong> <strong>right to distribute derivative works</strong>.</p>
<h3>How many sites and servers do you want to allow clients to use  your software on?</h3>
<p>This web-oriented clause restricts the client's use of the software to pre-determined number of sites / servers. While more relevant if you are selling a non-custom solution, it can still apply to custom solutions as well. You can also provide the right to use the software on unlimited sites / servers. A common approach is to offer different pricing (mostly for non-custom solutions) depending on the extent of use granted.</p>
<h3>Do you want to allow commercial use of your software?</h3>
<p>While this condition is true for most custom solutions, there are cases - such as when you are giving a discount to a non-profit - where you want to prohibit commercial use. It is common for off-the-shelf solutions to have a pricing strategy in which the basic product is given for free and commercial versions or extensions are sold for a fee. In order to allow that to happen, commercial use must be covered by the license.</p>
<p>There are basically three main options - royalty free commercial use, non-commercial use and commercial use with conditions. The last one states that commercial use is allowed if certain criteria are met (criteria that you need to decide upon and must be specified in the license).</p>
<h3>Do you want to allow clients to sell their license?</h3>
<p>Self explanatory. In legal terms - a license that allows license holders to sell their license and their right to use the software to a 3rd party, is called an <strong>assignable </strong>license. A license that restricts sale of the license is called a <strong>non-assignable &amp; non-transferable</strong> license.</p>
<h3>Do you want to grant your clients an exclusive license?</h3>
<p>An exclusive license allows you to sell your software to only one client (granting them exclusivity). This could be a requirement by a client, or your way to insure them that you will not be reselling the custom solution they paid you to develop. In most cases this only applies to custom solutions.</p>
<p><strong>This is just a partial list</strong> - there are many more minor restrictions and rights that can be included in a software license. We cover some of those in our <a href="http://www.binpress.com/page/licensing">licensing guide</a> on <a href="http://binpress.com">binpress</a>, and there even more less common clauses that can be applied. If you want to create a legally termed and binding software license using those conditions, we provide a commercial license generator for registered developers in our marketplace.</p>
<p>If you have any questions regarding any of the topics I covered, I would be happy to elaborate or even pass it on to our attorney. The next time you will be talking to clients about a potential project, be sure to have a ready software license that covers their rights and restrictions. This can save you much anguish and provide you with legal protection in the case that things go south.</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=538" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Software licenses for dummies" data-url="http://www.techfounder.net/2010/10/05/software-licenses-for-dummies/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2010/10/05/software-licenses-for-dummies/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Optimizing OR (union) operations in MySQL</title>
		<link>http://www.techfounder.net/2008/10/15/optimizing-or-union-operations-in-mysql/</link>
		<comments>http://www.techfounder.net/2008/10/15/optimizing-or-union-operations-in-mysql/#comments</comments>
		<pubDate>Wed, 15 Oct 2008 06:12:32 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=126</guid>
		<description><![CDATA[In my last post on database optimization, I focused on improving query performance by optimizing schema - exploring indexing strategies by reading the execution plan. In this post I'll show how different query structures can also have a major impact on performance. Dealing with OR operators in a WHERE clause of an SQL statement in [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.techfounder.net/2008/10/12/profiling-queries-with-zend_db-and-optimizing-them-by-hand/" title="Profiling MySQL queries with Zend_Db, optimizing by hand">last post</a> on database optimization, I focused on improving query performance by optimizing schema - exploring indexing strategies by reading the execution plan. In this post I'll show how different query structures can also have a major impact on performance.<br />
<span id="more-126"></span><br />
Dealing with OR operators in a WHERE clause of an SQL statement in MySQL can be tricky. Up until recently, MySQL could only use one index per table referenced in a query. A multi-column index can be used for  filtering conditions with an AND operator (which is more restrictive by nature), but a condition added by OR must use a separate index because of the logical nature of the opertaor (a <a href="http://en.wikipedia.org/wiki/Union_(set_theory)" target="_blank">union</a>, as opposed to an <a href="http://en.wikipedia.org/wiki/Intersection_(set_theory)">intersection</a> that the AND represents).</p>
<p>MySQL 5.0 added the <a href="http://dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html" target="_blank">index_merge</a> select type, which allows the query optimizer to possibly select several indexes from a single table and merge them to improve query performance. I say possibly, since leaving such decisions to the optimizer is risky at best. In fact, as I will show next, you are sometimes left with no indexes selected out of several possible options, resulting in a full table scan.</p>
<p>Continuing from my last post, I'll use a real-world example to show the different paths the queries optimizer can take when preparing an execution plan for our queries.</p>
<p>I'll actually be working with the same query I profiled last time, with a minor change. The relevant table structure is as follows:</p>
<pre class="sql"><span style="color: #808080; font-style: italic;">--</span>
<span style="color: #808080; font-style: italic;">-- Table structure for table `tasks`</span>
<span style="color: #808080; font-style: italic;">--</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`tasks`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">13</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span>,
  <span style="color: #ff0000;">`list_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">13</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`user_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">13</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`task`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> collate utf8_unicode_ci <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`due`</span> timestamp <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`created`</span> timestamp <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> CURRENT_TIMESTAMP,
  <span style="color: #ff0000;">`checked`</span> timestamp <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`assigned`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">13</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`done`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'1'</span><span style="color: #66cc66;">&#41;</span> collate utf8_unicode_ci <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`user_id`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`user_id`</span>,<span style="color: #ff0000;">`due`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`assigned`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`assigned`</span>,<span style="color: #ff0000;">`due`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`due`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`due`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> ENGINE=InnoDB</pre>
<p>And the query itself:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`id`</span>,
           <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`task`</span>,
           UNIX_TIMESTAMP<span style="color: #66cc66;">&#40;</span>due<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`time`</span>,
           <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`name`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_name`</span>,
           <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`tasks`</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`lists`</span> <span style="color: #993333; font-weight: bold;">ON</span> lists.id=tasks.list_id
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.user_id=<span style="color: #ff0000;">'1'</span> <span style="color: #993333; font-weight: bold;">OR</span> assigned=<span style="color: #ff0000;">'1'</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.done <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.due <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`due`</span> <span style="color: #993333; font-weight: bold;">ASC</span></pre>
<p>This query is almost the same as the one I worked with last time. The only difference being the first statement in the WHERE clause, involving an OR operator:</p>
<blockquote><p>(tasks.user_id='1' OR assigned='1')</p></blockquote>
<p>Just to understand what I'm doing here - The query selects from the tasks table with several filtering criteria. The last OR statement conveys the condition that the tasks selected either belong to specific user (i.e created by him) or assigned to him (those two possibly coincide).</p>
<p>For testing purposes I will be running the queries against a testing database I set up with plenty of mock data. The database is around 1Gb in total size, with the tasks table at about 1.8 million rows. It's not very large, but enough for significant data to be obtained while allowing relatively online tampering with schema (modifying keys takes <em>only</em> around 4 minutes to complete).</p>
<p>Running in original form computes as (average of 10 queries):</p>
<blockquote><p>(304 total, Query took 6.84 sec)</p></blockquote>
<p>6.84 sec is way too long for running a query in a typical web application. If you'd recall, I last got this query running at <strong>0.0008 sec</strong> without the additional OR condition, meaning it is running at around 7,000 times slower (yikes). In such a case you would suspect the indexes are not selective enough, and sure enough an EXPLAIN reveals:</p>
<table class="data" border="0">
<thead>
<tr>
<th>id</th>
<th>select_type</th>
<th>table</th>
<th>type</th>
<th>possible_keys</th>
<th>key</th>
<th>key_len</th>
<th>ref</th>
<th>rows</th>
<th>Extra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>tasks</td>
<td>index</td>
<td>user_id,assigned,due</td>
<td>due</td>
<td>5</td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">1875432</td>
<td>Using where</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
</tbody>
</table>
<p>MySQL is performing a regular index select and not an index_merge as we'd like, and doing that it selects the worst possible index - the only one that doesn't filter the result set. Sure enough, all 1.8M rows are scanned and the query is underperforming badly. Trying to force the issue, I first add an IGNORE INDEX(due) to remove it from the equation:</p>
<blockquote><p>(304 total, Query took 1.41 sec)</p></blockquote>
<table class="data" border="0">
<thead>
<tr>
<th>id</th>
<th>select_type</th>
<th>table</th>
<th>type</th>
<th>possible_keys</th>
<th>key</th>
<th>key_len</th>
<th>ref</th>
<th>rows</th>
<th>Extra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>tasks</td>
<td>ALL</td>
<td>user_id,assigned</td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">1870838</td>
<td>Using where; Using filesort</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
</tbody>
</table>
<p>The query optimizer has decided not to use an index at all, despite several good candidates. However, query performance is improved since a full table scan with no index is performed straight up. It's still way too slow, and we'd like it to use a filtering index so it can avoid a full table scan. Trying to force the other indexes doesn't work so we're left with no choice but to try alternative query structures.</p>
<p>Our first candidate is replacing our OR condition with two UNION'ed select statements (the inspiration is from a <a href="http://www.mysqlperformanceblog.com/2007/09/18/possible-optimization-for-sort_merge-and-union-order-by-limit/" target="_blank">couple</a> of <a href="http://www.mysqlperformanceblog.com/2007/10/05/union-vs-union-all-performance/" target="_blank">posts</a> over at the MySQL performance blog). Breaking the original query into a UNION form results in:</p>
<pre class="sql"><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`id`</span>,
            <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`task`</span>,
            UNIX_TIMESTAMP<span style="color: #66cc66;">&#40;</span>due<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`time`</span>,
            <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`name`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_name`</span>,
            <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`tasks`</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`lists`</span> <span style="color: #993333; font-weight: bold;">ON</span> lists.id=tasks.list_id
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.done <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.due <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.user_id=<span style="color: #ff0000;">'1'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> UNION <span style="color: #993333; font-weight: bold;">ALL</span> <span style="color: #66cc66;">&#40;</span>
 <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`id`</span>,
            <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`task`</span>,
            UNIX_TIMESTAMP<span style="color: #66cc66;">&#40;</span>due<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`time`</span>,
            <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`name`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_name`</span>,
            <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`tasks`</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`lists`</span> <span style="color: #993333; font-weight: bold;">ON</span> lists.id=tasks.list_id
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.done <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.due <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>assigned=<span style="color: #ff0000;">'1'</span> <span style="color: #993333; font-weight: bold;">AND</span> tasks.user_id!=<span style="color: #ff0000;">'1'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`time`</span> <span style="color: #993333; font-weight: bold;">ASC</span>
&nbsp;</pre>
<p>This unsightly looking query looks much more complex, but actually gets the job done:</p>
<blockquote><p>(304 total, Query took 0.0021 sec)</p></blockquote>
<p>A big improvement to say the least (~3500 faster than the original query).<br />
The explain shows why:</p>
<table class="data" border="0">
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>PRIMARY</td>
<td>tasks</td>
<td>range</td>
<td>user_id,due</td>
<td>user_id</td>
<td>9</td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">304</td>
<td>Using where</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>PRIMARY</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
<tr class="odd">
<td class="nowrap" align="right">2</td>
<td>UNION</td>
<td>tasks</td>
<td>range</td>
<td>user_id,assigned,due</td>
<td>assigned</td>
<td>10</td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">1</td>
<td>Using where</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">2</td>
<td>UNION</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
<tr class="odd">
<td align="right"><em>NULL</em></td>
<td>UNION RESULT</td>
<td>&lt;union1,2&gt;</td>
<td>ALL</td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td align="right"><em>NULL</em></td>
<td>Using filesort</td>
</tr>
</tbody>
</table>
<p>Only 304 rows are scanned (as opposed to the entire 1.8M table before). Despite the filesort, we are in the area of usability for this query.</p>
<p>Another approach would be to determine why the index_merging isn't take place and how can we enforce it. By reducing the WHERE clause to include only the columns covered by an index, index_merging kicks in resulting in a similar performance as the union, albeit with less selective filtering:</p>
<blockquote><p>(368 total, Query took 0.0018 sec)</p></blockquote>
<p>We could filter our result set in the application, but I'd like to keep it in the SQL where it belongs. In order to integrate the rest of the filtering statements, I use an IN condition on another index I have available - the primary key. This results in:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`id`</span>,
           <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`task`</span>,
           UNIX_TIMESTAMP<span style="color: #66cc66;">&#40;</span>due<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`time`</span>,
           <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`name`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_name`</span>,
           <span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`tasks`</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`lists`</span> <span style="color: #993333; font-weight: bold;">ON</span> lists.id=tasks.list_id
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.user_id=<span style="color: #ff0000;">'1'</span> <span style="color: #993333; font-weight: bold;">OR</span> assigned=<span style="color: #ff0000;">'1'</span><span style="color: #66cc66;">&#41;</span>
   <span style="color: #993333; font-weight: bold;">AND</span> tasks.id <span style="color: #993333; font-weight: bold;">IN</span>
     <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> id
      <span style="color: #993333; font-weight: bold;">FROM</span> tasks
      <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.done <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.due <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`due`</span> <span style="color: #993333; font-weight: bold;">ASC</span>
&nbsp;</pre>
<p>Which brings us back to the performance levels of the UNION form:</p>
<blockquote><p>(304 total, Query took 0.0021 sec)</p></blockquote>
<p>And we can see in the EXPLAIN that it is indeed an index_merge operation:</p>
<table class="data" border="0">
<thead>
<tr>
<th>id</th>
<th>select_type</th>
<th>table</th>
<th>type</th>
<th>possible_keys</th>
<th>key</th>
<th>key_len</th>
<th>ref</th>
<th>rows</th>
<th>Extra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>PRIMARY</td>
<td>tasks</td>
<td>index_merge</td>
<td>user_id,assigned</td>
<td>user_id,assigned</td>
<td>4,5</td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">369</td>
<td>Using sort_union(user_id,assigned); Using where; Using filesort</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>PRIMARY</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
<tr class="odd">
<td class="nowrap" align="right">2</td>
<td>DEPENDENT SUBQUERY</td>
<td>tasks</td>
<td>unique_subquery</td>
<td>PRIMARY,due</td>
<td>PRIMARY</td>
<td>4</td>
<td>func</td>
<td class="nowrap" align="right">1</td>
<td>Using where</td>
</tr>
</tbody>
</table>
<p>So there you have it. From 6.83 seconds to 0.0021 seconds with some tweaking to the query structure. I am still not completely satisfied with the fact that it's using filesort, but I couldn't get it to use another index for the operation. Without the sorting the query is twice as fast:</p>
<blockquote><p>(304 total, Query took 0.0010 sec)</p></blockquote>
<p>So if it ever becomes an issue I could move sorting to the application code. Hopefully by then merge_index is better implemented in MySQL.</p>
<p>Regarding the query strucutre - personally I use the subquery format since it is more compact and maintainable. It is always good however to be familiar with all the alternatives.</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=126" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Optimizing OR (union) operations in MySQL" data-url="http://www.techfounder.net/2008/10/15/optimizing-or-union-operations-in-mysql/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/10/15/optimizing-or-union-operations-in-mysql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Profiling queries with Zend_Db and optimizing them by hand</title>
		<link>http://www.techfounder.net/2008/10/12/profiling-queries-with-zend_db-and-optimizing-them-by-hand/</link>
		<comments>http://www.techfounder.net/2008/10/12/profiling-queries-with-zend_db-and-optimizing-them-by-hand/#comments</comments>
		<pubDate>Sun, 12 Oct 2008 05:42:55 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[profiling]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=125</guid>
		<description><![CDATA[Database performance is one of the major bottlenecks for most web applications. Most web developers are not database experts (and I'm no exception), there are however several basic methods to analyze and optimize database performance without resorting to expert consultants (such as those, whose founders blogs are an invaluable source of MySQL knowledge). The Performance [...]]]></description>
			<content:encoded><![CDATA[<p>Database performance is one of the major bottlenecks for most web applications. Most web developers are not database experts (and I'm no exception), there are however several basic methods to analyze and optimize database performance without resorting to expert consultants (such as <a href="http://www.percona.com/">those</a>, whose founders blogs are an <a href="http://www.mysqlperformanceblog.com/">invaluable</a> <a href="http://www.xaprb.com/blog/">source</a> of MySQL knowledge).<br />
<span id="more-125"></span></p>
<h3>The Performance Equation</h3>
<p>Database performance is affected by many different variables - the running machine specs, OS, database engine and configuration, table schema and the queries running against it. Since I'm dealing mostly (only?) with MySQL, this article covers it mainly (though it is probably relevant to a large degree for other engines). As for OS and machine specs, I'll take them out of the equation as I'm interested in optimizing <strong>relative</strong> performance on the same machine.</p>
<p>Basically I'm interested in optimizing:</p>
<ul>
<li>The structure of my database tables (schema)</li>
<li>The structure of my application-level queries (SELECT, UPDATE, INSERT, DELETE)</li>
</ul>
<h3>Profiling Database Performance</h3>
<p>Blindly optimizing queries and database schema is counter-productive.  First we should <em>know</em> what we should be optimizing, and for that we need data. The act of gathering data for optimization is called profiling or <a href="http://en.wikipedia.org/wiki/Performance_analysis">performance analysis</a>.</p>
<p>The first step I take when profiling database performance for a web app is to measure the running time of all the queries running in it. Absolute run time of a query is not necessarily a good measure of how optimized / performant it is, since some queries are naturally more complex or pull more data - It will give me a good idea however of where to start improving the response time of the application I'm optimizing. My main goal is not specific query performance, but overall system performance.</p>
<p>Measuring the run time of a query can be done with simple timers using <a title="PHP: microtime()" href="http://www.php.net/microtime">microtime()</a> calls (Check out <a href="http://www.coderholic.com/php-profile-class/">this post</a> for an abstraction), running it in a tool that automatically provides such statistics (phpMyAdmin for example) or using an integrated profiler.</p>
<p>I am using the <a title="Zend_Db_Profiler" href="http://framework.zend.com/manual/en/zend.db.profiler.html">Zend_Db_Profiler,</a> which is convenient for me since I'm using the Zend Framework and all database access converges to a Zend_Db_Adapter connection. The profiler basically uses the microtime() approach but integrates it transparently into all of the queries without me having to wrap them one by one.</p>
<p>Usage is pretty simple. First you need to pass an extra parameter to your Zend_Db_Adapter instance to activate profiling:</p>
<pre class="php"><span style="color: #0000ff;">$params</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span>
    <span style="color: #ff0000;">'host'</span>     =&gt; <span style="color: #ff0000;">'localhost'</span>,
    <span style="color: #ff0000;">'username'</span> =&gt; <span style="color: #ff0000;">'dbusername'</span>,
    <span style="color: #ff0000;">'password'</span> =&gt; <span style="color: #ff0000;">'dbpassword'</span>,
    <span style="color: #ff0000;">'dbname'</span>   =&gt; <span style="color: #ff0000;">'dbname'</span>,
    <span style="color: #ff0000;">'profiler'</span> =&gt; <span style="color: #000000; font-weight: bold;">true</span>  <span style="color: #808080; font-style: italic;">// turn on profiler, disabled by default</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #0000ff;">$db</span> = Zend_Db::<span style="color: #006600;">factory</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'PDO_MYSQL'</span>, <span style="color: #0000ff;">$params</span><span style="color: #66cc66;">&#41;</span>;</pre>
<p>The Zend Framework manual shows some advanced usage (such as profiling directly into firebug, which is very convenient), however for our purposes we simply want to dump the queries and their run time.</p>
<pre class="php"><span style="color: #0000ff;">$profiler</span> = <span style="color: #0000ff;">$db</span> -&gt; <span style="color: #006600;">getProfiler</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #0000ff;">$profile</span> = <span style="color: #ff0000;">''</span>;
<span style="color: #b1b100;">foreach</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$profiler</span> -&gt; <span style="color: #006600;">getQueryProfiles</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #0000ff;">$query</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
	<span style="color: #0000ff;">$profile</span> .= <span style="color: #0000ff;">$query</span> -&gt; <span style="color: #006600;">getQuery</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> . <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
	     . <span style="color: #ff0000;">'Time: '</span> . <span style="color: #0000ff;">$query</span> -&gt; <span style="color: #006600;">getElapsedSecs</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #0000ff;">$profile</span>;</pre>
<p>This snippet goes of course after the view has been rendered and all queries executed.</p>
<h3>Using a relevant dataset</h3>
<p>It's important to know whether the data you are profiling against is relevant for when you believe you will start hitting performance issues. Granted, you can never really know when will that be, however it is always preferable to work with a dataset that resembles your (projected) production environment.</p>
<p>I will walk through a specific use-case I recently went through while preparing for the beta release of my startup, business platform Octabox (since defunct).</p>
<p>Running the profiler on one of the views in the application produced the following output on my development machine:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`type`</span>, <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`action`</span>, <span style="color: #ff0000;">`tags`</span>.<span style="color: #ff0000;">`color`</span>, <span style="color: #ff0000;">`tags`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`tag_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`history`</span>
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`tags`</span>
<span style="color: #993333; font-weight: bold;">ON</span> tags.id=history.tag_id <span style="color: #993333; font-weight: bold;">AND</span> tags.user_id=<span style="color: #cc66cc;">1</span>
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>history.user_id=<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>history.logged_on &gt;= <span style="color: #ff0000;">'2008-09-27 00:00:00'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`logged_on`</span> <span style="color: #993333; font-weight: bold;">DESC</span></pre>
<p><strong>Time: 0.00269</strong></p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`task`</span>,<span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`tasks`</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`lists`</span> <span style="color: #993333; font-weight: bold;">ON</span> lists.id=tasks.list_id
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.done <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.due <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.user_id=<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`due`</span> <span style="color: #993333; font-weight: bold;">ASC</span></pre>
<p><strong>Time: 0.000592</strong></p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> COUNT<span style="color: #66cc66;">&#40;</span>*<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`count`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`dispatch`</span>
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>dispatch.user_id=<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>dispatch.<span style="color: #993333; font-weight: bold;">STATUS</span>=<span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span></pre>
<p><strong>Time: 0.00044</strong></p>
<p>At first sight it would appear that the first query would be our immediate suspect for optimization, though the gains would not be great (completes in just over 0.002 seconds). Switching to a database I've prepared before hand with plenty of dummy data (~1.1Gb, some tables over 5M rows) the output looks very different:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`type`</span>, <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`action`</span>, <span style="color: #ff0000;">`tags`</span>.<span style="color: #ff0000;">`color`</span>, <span style="color: #ff0000;">`tags`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`tag_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`history`</span>
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`tags`</span>
<span style="color: #993333; font-weight: bold;">ON</span> tags.id=history.tag_id <span style="color: #993333; font-weight: bold;">AND</span> tags.user_id=<span style="color: #cc66cc;">1</span>
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>history.user_id=<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>history.logged_on &gt;= <span style="color: #ff0000;">'2008-09-27 00:00:00'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`history`</span>.<span style="color: #ff0000;">`logged_on`</span> <span style="color: #993333; font-weight: bold;">DESC</span></pre>
<p><strong>Time: 0.000426</strong></p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`task`</span>,<span style="color: #ff0000;">`lists`</span>.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`list_id`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`tasks`</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`lists`</span> <span style="color: #993333; font-weight: bold;">ON</span> lists.id=tasks.list_id
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>tasks.done <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.due <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>tasks.user_id=<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`tasks`</span>.<span style="color: #ff0000;">`due`</span> <span style="color: #993333; font-weight: bold;">ASC</span></pre>
<p><strong>Time: 58.16</strong> <em>//Hmmm... problem?</em></p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> COUNT<span style="color: #66cc66;">&#40;</span>*<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`count`</span>
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`dispatch`</span>
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span>dispatch.user_id=<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span>dispatch.<span style="color: #993333; font-weight: bold;">STATUS</span>=<span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span></pre>
<p><strong>Time: 0.000322</strong></p>
<p>A query that took just over 0.0005 seconds on a small database, took almost a minute to complete on a bigger one. Surprisingly enough the other queries remained blazingly fast (even faster than on my development machine with a small database, which is a credit to our server's power).</p>
<h3>Optimizing The Errant Query</h3>
<p>So I've found a very problematic query to say the least. Taking 58.1 seconds to complete is obviously not acceptable for any real time application. Running EXPLAIN against the query revealed the following execution plan:</p>
<table class="data" border="0">
<thead>
<tr>
<th>id</th>
<th>select_type</th>
<th>table</th>
<th>type</th>
<th>possible_keys</th>
<th>key</th>
<th>key_len</th>
<th>ref</th>
<th>rows</th>
<th>Extra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>tasks</td>
<td>index</td>
<td>user_id</td>
<td>user_id</td>
<td>9</td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">1868081</td>
<td>Using where</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
</tbody>
</table>
<p>The EXPLAIN results show the most immediate problem with the query - it was performing a join against every row in a 1.8M row table.</p>
<p>Examining the details of the query plan, it appears both selects are using an index, the first one limited by a WHERE (on the surface at least - since all rows were scanned). Since despite using an index the entire table was scanned very slowly, I tried to see the query will respond if I removed the index. Using IGNORE INDEX(user_id), I re-ran the query (this time in the Mysql command line):</p>
<blockquote><p>304 rows in set (<strong>1.53 sec</strong>)</p></blockquote>
<p>Wow, that's a big difference <strong>for not using</strong> an index. Running EXPLAIN on this reveals:</p>
<table class="data" border="0">
<thead>
<tr>
<th>id</th>
<th>select_type</th>
<th>table</th>
<th>type</th>
<th>possible_keys</th>
<th>key</th>
<th>key_len</th>
<th>ref</th>
<th>rows</th>
<th>Extra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>tasks</td>
<td>ALL</td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td><em>NULL</em></td>
<td class="nowrap" align="right">1866244</td>
<td>Using where; Using filesort</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
</tbody>
</table>
<p>Despite using filesort to sort the query, it was running almost <strong>30 times</strong> faster than before. By forcing it not to use an index which was not selective enough (i.e. not at all), the query ran a full table scan instead and completed much faster due to a better execution plan.</p>
<p>So we've improved greatly, but still not enough for my needs. Having one query taking over a second to complete when all the others are completing in sub 0.01 second times means it will be a bottleneck as the database grows (remember, the same query completed in just over 0.0005 seconds on a much smaller database).</p>
<p>Examining the structure of the table in question (tasks) revealed another interesting revelation - there is <strong>no index</strong> on the user_id column. So what happened? it appears there used to be an index on the user_id column, however it was removed just before all the dummy data was inserted into the database. Running ANALYZE TABLE tasks repaired the key information to the current state (no index on user_id).</p>
<p>I wanted to try the original query, this time with an actual index on the filtering column (user_id). After adding the index, I re-ran the query:</p>
<blockquote><p>(304 total, Query took <strong>0.0021 sec</strong>)</p></blockquote>
<p>Much better! but I was not done. Running EXPLAIN yet again reveals the following execution plan:</p>
<table class="data" border="0">
<thead>
<tr>
<th>id</th>
<th>select_type</th>
<th>table</th>
<th>type</th>
<th>possible_keys</th>
<th>key</th>
<th>key_len</th>
<th>ref</th>
<th>rows</th>
<th>Extra</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>tasks</td>
<td>ref</td>
<td>user_id</td>
<td>user_id</td>
<td>4</td>
<td>const</td>
<td class="nowrap" align="right">368</td>
<td>Using where; Using filesort</td>
</tr>
<tr class="even">
<td class="nowrap" align="right">1</td>
<td>SIMPLE</td>
<td>lists</td>
<td>eq_ref</td>
<td>PRIMARY</td>
<td>PRIMARY</td>
<td>4</td>
<td>tasks.list_id</td>
<td class="nowrap" align="right">1</td>
<td></td>
</tr>
</tbody>
</table>
<p>So indeed, using <strong>an actual index</strong> was a big help, filtering the set to only 368 rows before processing the rest of the query. However, you'd notice it is running a filesort which we'd like to avoid. Preferably, I could set up an index combination that both filters and sorts using an index.</p>
<p>Creating an index composed of both the 'user_id' and 'due' columns got it right on the head, leading to:</p>
<blockquote><p>(304 total, Query took <strong>0.0008 sec</strong>)</p></blockquote>
<p>Not as dramatic as previous improvements, but still three times better than the last iteration.</p>
<h3>Final Words</h3>
<p>The entire process took several hours of head scratching to arrive at all the results I've shown here. I managed to take a query that would cripple our server (58 seconds for one completion!) to an extremely fast one (0.0008 seconds against a 1.8M row table), through the use of some basic profiling and examining the execution plan.</p>
<p>Being an edge case (a non existent index used to filter against a 1.8M row table...), I gained valuable experience on potential pitfalls and on reading between the lines in the execution plan.</p>
<p>Some technical gibberish:</p>
<p>All queries were run with SQL_NO_CACHE to prevent caching from tampering with the results. I ran each query at least 5 times to make sure I was getting the right readings.</p>
<p>The specs of the server machine that ran the queries are as follows:</p>
<ul>
<li>Intel \ 2.4 GHz 1066FSB - Conroe \ Xeon 3060 (Dual Core)</li>
<li>2 x Generic \ 1024 MB \ DDR2 667 ECC</li>
<li>2 x Maxtor \ 146GB:SAS:10K RPM \ Atlas 10K - SAS</li>
<li>CentOS Enterprise Linux - x86_64 - OS ES 5.0</li>
<li>Running PHP 5.2.6 with MySQL 5.0.45 on Apache 2.2.4</li>
</ul>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=125" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Profiling queries with Zend_Db and optimizing them by hand" data-url="http://www.techfounder.net/2008/10/12/profiling-queries-with-zend_db-and-optimizing-them-by-hand/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/10/12/profiling-queries-with-zend_db-and-optimizing-them-by-hand/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Chrome is out. Google has my vote</title>
		<link>http://www.techfounder.net/2008/09/04/chrome-is-out-google-has-my-vote/</link>
		<comments>http://www.techfounder.net/2008/09/04/chrome-is-out-google-has-my-vote/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 21:36:24 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[The Webs]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=120</guid>
		<description><![CDATA[So Google Chrome was unleashed on the unsuspecting public yesterday with very little preceding hype. It enters a market that has thus far has had only two major players - Mozilla and Microsoft. Backed by marketing power that is unrivaled in the online world, it is strongly positioned to take both on (and especially Microsoft). [...]]]></description>
			<content:encoded><![CDATA[<p>So Google Chrome was unleashed on the unsuspecting public yesterday with very little preceding hype. It enters a market that has thus far has had only two major players - Mozilla and Microsoft. Backed by marketing power that is unrivaled in the online world, it is strongly positioned to take both on (and especially Microsoft).</p>
<p>A web browser built on the webkit engine (same as Safari), Chrome offers a simple UI and extensive support for web technologies. Having used it for a couple of days now, it is striking to me how obvious it is that Google is a web company - in bold contrast to another software giant currently pushing for their next-gen browser.</p>
<p><span id="more-120"></span></p>
<p>There is a lot to like about Chrome: <strong>It is open-source</strong>. The tab oriented UI is a great innovation. The simple UI allows for an impressively large work area in the browser. It comes with a built in DOM inspector and Javascript debugger (almost rivaling Firebug for functionality). The tab/process manager is an awesome feature (though <a title="John Resign on Chrome process manager" href="http://ejohn.org/blog/google-chrome-process-manager" target="_blank">a possible source of contention</a>). And most importantly - aside from minor inconsistencies from the standards (shared by Safari), all web sites render perfectly under Chrome.</p>
<p>I was somehow surprised though it only reaches a score of 79 on the acid3 test, since it is based on an engine that already scored a perfect 100 (webkit). For comparison, Firefox 3.0.1 achieves a score of 71 (though with less graphical glitches), IE7 achieves a measly score of 13 in about triple the time, and IE8 beta 2 just barely beats that with a very low 21.</p>
<p>It is my personal hope that Chrome steals enough market share from Microsoft to help push out older IE versions, thus catapulting the web forward. This has been a fantastic move by Google, and the online world is watching to see how the market will respond. Is a Google OS next on the agenda?</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=120" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Chrome is out. Google has my vote" data-url="http://www.techfounder.net/2008/09/04/chrome-is-out-google-has-my-vote/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/09/04/chrome-is-out-google-has-my-vote/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Handling mail and mime in PHP using the Zend Framework</title>
		<link>http://www.techfounder.net/2008/07/18/handling-mail-and-mime-in-php-using-the-zend-framework/</link>
		<comments>http://www.techfounder.net/2008/07/18/handling-mail-and-mime-in-php-using-the-zend-framework/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 04:43:40 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[zend_mail]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=97</guid>
		<description><![CDATA[Handling mail is a very common requirement in web applications. Even the most basic sites usually have a contact form that sends a mail through the server instead of putting a contact mail address for spam-spiders to find. Using PHP's built in function (aptly named mail() ) is relatively straightforward - until you need slightly [...]]]></description>
			<content:encoded><![CDATA[<p>Handling mail is a very common requirement in web applications. Even the most basic sites usually have a contact form that sends a mail through the server instead of putting a contact mail address for spam-spiders to find. Using PHP's built in function (aptly named <a href="http://www.php.net/function.mail" target="_blank">mail()</a> ) is relatively straightforward - until you need slightly more advanced features, such as adding and encoding email headers or sending multiple mails efficiently.<br />
<span id="more-97"></span><br />
Fortunately, the Zend Framework comes with a very capable mail component called <a href="http://framework.zend.com/manual/en/zend.mail.html" target="_blank">Zend_Mail</a>. Zend_Mail abstracts some of the more tedious aspects of mail handling with PHP, including:</p>
<ol>
<li>Adding and encoding email headers</li>
<li>Protection against <a href="http://www.php-security.org/MOPB/MOPB-34-2007.html" target="_blank">header injection</a></li>
<li>Multiple mail transports (SMTP is useful for sending multiple mails)</li>
<li>Creating and handling mime-compliant multipart messages</li>
<li>Composing HTML emails</li>
<li>Reading mail boxes</li>
</ol>
<h2>Sending mails</h2>
<p>Using Zend_Mail is extremely straightforward: (Taken from the ZF documentation)</p>
<pre class="php"> <span style="color: #b1b100;">require_once</span> <span style="color: #ff0000;">'Zend/Mail.php'</span>;
<span style="color: #0000ff;">$mail</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$mail</span>-&amp;gt;setBodyText<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'This is the text of the mail.'</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">//Alternatively using setBodyHtml for HTML messages</span>
<span style="color: #0000ff;">$mail</span>-&amp;gt;setFrom<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'somebody@example.com'</span>, <span style="color: #ff0000;">'Some Sender'</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">//Adds a 'from' header</span>
<span style="color: #0000ff;">$mail</span>-&amp;gt;addTo<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'somebody_else@example.com'</span>, <span style="color: #ff0000;">'Some Recipient'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$mail</span>-&amp;gt;setSubject<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'TestSubject'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$mail</span>-&amp;gt;send<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;</pre>
<p>Simple.</p>
<p>For sending multiple mails it is better to use the SMTP protocol for performance reasons. Doing this manually with PHP is <a href="http://www.mustap.com/phpzone_post_95_sending-email-in-php-the-hac" target="_blank">quite elaborate</a> however, but with Zend_Mail it is almost as simple as before:</p>
<pre class="php"> <span style="color: #b1b100;">require_once</span> <span style="color: #ff0000;">'Zend/Mail.php'</span>;
&nbsp;
<span style="color: #808080; font-style: italic;">// Create transport</span>
<span style="color: #b1b100;">require_once</span> <span style="color: #ff0000;">'Zend/Mail/Transport/Smtp.php'</span>;
<span style="color: #0000ff;">$transport</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail_Transport_Smtp<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'localhost'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #808080; font-style: italic;">// Sending out multiple mails at once</span>
<span style="color: #b1b100;">for</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$i</span> = <span style="color: #cc66cc;">0</span>; <span style="color: #0000ff;">$i</span> &amp;gt; <span style="color: #cc66cc;">5</span>; <span style="color: #0000ff;">$i</span>++<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0000ff;">$mail</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$mail</span>-&amp;gt;addTo<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'studio@peptolab.com'</span>, <span style="color: #ff0000;">'Test'</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$mail</span>-&amp;gt;setFrom<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'studio@peptolab.com'</span>, <span style="color: #ff0000;">'Test'</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$mail</span>-&amp;gt;setSubject<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'Demonstration - Sending Multiple Mails per SMTP Connection'</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$mail</span>-&amp;gt;setBodyText<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'...Your message here...'</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$mail</span>-&amp;gt;send<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$transport</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">//Using the SMTP transport for sending the mail</span>
<span style="color: #66cc66;">&#125;</span></pre>
<p>* SMTP connections <a href="http://framework.zend.com/manual/en/zend.mail.smtp-secure.html">can be secured with SSL or TLS</a> for sending sensitive mails.</p>
<p>This procedure reuses the SMTP connection for the lifetime of the entire process which is much better than sending out mails using the mail() function.</p>
<h2>Reading mail boxes</h2>
<p>Reading mail boxes is similarly simple. Zend_Mail supports POP3 and IMAP for remote connections, and Mbox and Maildir for local connections (mail boxes residing on the same server). Sample usage:</p>
<pre class="php"><span style="color: #0000ff;">$mail</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail_Storage_Pop3<span style="color: #66cc66;">&#40;</span> <span style="color: #808080; font-style: italic;">//Configuring with host and credentials</span>
	<a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'host'</span> =&amp;gt; <span style="color: #ff0000;">'example.com'</span>,
	      <span style="color: #ff0000;">'user'</span> =&amp;gt; <span style="color: #ff0000;">'test'</span>,
	      <span style="color: #ff0000;">'password'</span> =&amp;gt; <span style="color: #ff0000;">'test'</span>
	<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #0000ff;">$mail</span>-&amp;gt;countMessages<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> . <span style="color: #ff0000;">&quot; messages found<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>; <span style="color: #808080; font-style: italic;">//Outputting message count in mail box</span>
<span style="color: #b1b100;">foreach</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$mail</span> <span style="color: #b1b100;">as</span> <span style="color: #0000ff;">$message</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> <span style="color: #808080; font-style: italic;">//Outputting message subjects</span>
    <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">&quot;Mail from &quot;</span> . <span style="color: #0000ff;">$message</span>-&amp;gt;from . <span style="color: #ff0000;">&quot;: &quot;</span> . <span style="color: #0000ff;">$message</span>-&amp;gt;subject . <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>;
<span style="color: #66cc66;">&#125;</span></pre>
<p>Using the different storage options is very similar. Messages returned are instances of the Zend_Mail_Message class, which provides an API for manipulating mail messages.</p>
<h2>Advanced Usage</h2>
<p>Working with multipart MIME messages is very tedious. The <a href="http://www.faqs.org/rfcs/rfc1521.html" target="_blank">MIME specifications</a> are rather complex and MIME messages aren't very readable to humans, and therefor we would like to be able to use Zend_Mail_Message API to reduce the pains of dealing with MIME messages. There are several general cases when working with MIME messages:</p>
<ol>
<li>Working with messages which are stored as strings in a database</li>
<li>Working with messages which are read from files</li>
<li>Working with incoming messages directly (from an <a href="http://www.php.net/wrappers.php" target="_blank">input stream</a>)</li>
</ol>
<p>Zend_Mail_Messsage can receive either a raw message string in its constructor, a file name or a file handle. Examples of instancing a Zend_Mail_Message object with all three:</p>
<pre class="php"><span style="color: #808080; font-style: italic;">//From a raw string</span>
<span style="color: #0000ff;">$message</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail_Message<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'raw'</span> =&amp;gt; <span style="color: #0000ff;">$rawMessage</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; 
&nbsp;
<span style="color: #808080; font-style: italic;">//From a file name</span>
<span style="color: #0000ff;">$message</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail_Message<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'file'</span> =&amp;gt; <span style="color: #ff0000;">'/path/to/mail/message'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #808080; font-style: italic;">//From a file handle</span>
<span style="color: #0000ff;">$handle</span> = <a href="http://www.php.net/fopen"><span style="color: #000066;">fopen</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'/path/to/mail/message'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$message</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail_Message<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'file'</span> =&amp;gt; <span style="color: #0000ff;">$handle</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</pre>
<p>The last one might seem a bit redundant. However it opens up creative ways to intercept mail directly using the input wrapper:</p>
<pre class="php"><span style="color: #0000ff;">$handle</span> = <a href="http://www.php.net/fopen"><span style="color: #000066;">fopen</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;php://stdin&quot;</span>, <span style="color: #ff0000;">&quot;r&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$message</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Mail_Message<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'file'</span> =&amp;gt; <span style="color: #0000ff;">$handle</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</pre>
<p>The tricky part is directing the mail message stream into the script. You can read more about that in this <a href="http://www.evolt.org/article/Incoming_Mail_and_PHP/18/27914/index.html" target="_blank">nice tutorial from evolt</a>.</p>
<h2>Some minor bugs and fixes</h2>
<p>Nothing is perfect however. Current version of Zend_Mail (shipped with the Zend_Framework ver. 1.5.2) has a buggy implementation of the headers encoding. This will become noticeable when working with UTF encoded mails. Fortunately there is a <a href="http://framework.zend.com/issues/browse/ZF-3641">quick fix for that</a> posted in the ZF issue tracker (and hopefully will be tested and integrated in the next release).</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=97" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Handling mail and mime in PHP using the Zend Framework" data-url="http://www.techfounder.net/2008/07/18/handling-mail-and-mime-in-php-using-the-zend-framework/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/07/18/handling-mail-and-mime-in-php-using-the-zend-framework/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Content syndication needs rebranding</title>
		<link>http://www.techfounder.net/2008/07/01/content-syndication-needs-rebranding/</link>
		<comments>http://www.techfounder.net/2008/07/01/content-syndication-needs-rebranding/#comments</comments>
		<pubDate>Tue, 01 Jul 2008 02:04:59 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[The Webs]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=52</guid>
		<description><![CDATA[Content syndication or Feeds, is a mashup of technologies that provides an easy way to keep track of updates from multiple content sources. Despite being very useful, it has yet to find widespread acceptance amongst Internet users. Direct usage statistics are hard to ascertain with great precision, but they revolve around 4%-6% of the total [...]]]></description>
			<content:encoded><![CDATA[<p>Content syndication or <a title="Wikipedia: Web Feeds" href="http://en.wikipedia.org/wiki/Web_feed" target="_blank">Feeds</a>, is a mashup of technologies that provides an easy way to keep track of updates from multiple content sources. Despite being very useful, it has yet to find widespread acceptance amongst Internet users.</p>
<p>Direct usage statistics are hard to ascertain with great precision, but they revolve around 4%-6% of the total Internet population, which is not much. More feeds are being consumed indirectly by aggregation sites, such as my yahoo and iGoogle (as this <a title="Yahoo! on RSS feeds" href="http://publisher.yahoo.com/rss/RSS_whitePaper1004.pdf " target="_blank">Yahoo! paper</a> shows), which shows that there is market ready to consume more feeds.</p>
<p>So why feed usage isn't more widespread?<span id="more-52"></span></p>
<p>1. Lack of awareness<br />
Most people are simply unaware of the benefits of using feeds. When asked about what are feeds, only 12% of the Internet public were aware of its meaning. I will admit myself to be one of the ignorant up until not too long ago (about 6 months). For me that is mind boggling - I consider myself an extremely technical user and I love the Internet. How was I not aware of how useful this technology is?</p>
<p>2. Confusing terminology<br />
What is a feed? syndication? aggregators? to someone hearing those terms for the first time it can be very discouraging. There is alternative terminology such as subscriptions and readers which is more similar to natural language but it isn't used enough to explain the technology.</p>
<p>3. Competing standards<br />
<a title="Wikipedia: Atom\" href="http://en.wikipedia.org/wiki/Atom_%28standard%29" target="_blank">Atom</a> and <a title="Wikipedia: RSS" href="http://en.wikipedia.org/wiki/RSS_(file_format)" target="_blank">RSS</a> are competing standards for web syndication. Both are offering basically the same solution, so why haven't they merged yet? (actually <a title="Wikipedia: Barriers to adoption" href="http://en.wikipedia.org/wiki/Atom_%28standard%29#Barriers_to_adoption" target="_blank">there are reasons</a>, but not very good ones). Most sites now offer both, which only add to the confusion as the names of the different formats are sometimes use interchangeably with the term Feed.</p>
<p>Content syndication is just waiting to erupt. Someone needs to take initiative and promote this technology to the masses:</p>
<p>1. Create awareness<br />
The same way open standards such as OpenID made a splash some time ago, content syndication needs visibility. And in contrast to open standards, web syndication is useful now.</p>
<p>2. Improve description<br />
Hand in hand in creating visibility, a low-tech explanation of the benefits of syndication should be drafted and used liberally. This will go a long way to break the barriers of adoption.</p>
<p>3. Unify standards<br />
One to rule them all as they say. Since this is an open standard and certainly not for profit, the only real consideration would be backwards compatibility. Declare RSS officially as the standby for compatibility and Atom as the active standard for future development.</p>
<p>4. Do not call the technology by its standards name!<br />
Stop using RSS or Atom feeds as the name for the subscription feature. People are much more likely to hit 'Subscribe' than 'Join my RSS feeds'...</p>
<p>P.S.<br />
Syndication always reminds me of the PC classic '<a title="Home of the underdogs: Syndicate" href="http://www.the-underdogs.info/game.php?gameid=1916" target="_blank">Syndicate</a>' in which rival clans fight for world domination in a futuristic setting using cyborg agents. Good times...</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=52" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Content syndication needs rebranding" data-url="http://www.techfounder.net/2008/07/01/content-syndication-needs-rebranding/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/07/01/content-syndication-needs-rebranding/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery and Prototype the choice of top websites</title>
		<link>http://www.techfounder.net/2008/06/14/jquery-and-prototype-the-choice-of-top-websites/</link>
		<comments>http://www.techfounder.net/2008/06/14/jquery-and-prototype-the-choice-of-top-websites/#comments</comments>
		<pubDate>Sat, 14 Jun 2008 00:54:59 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=68</guid>
		<description><![CDATA[Pingdom has complied a list of the Javascript frameworks used by the top sites on the web (top 100 in Alexa US, Webware's top 100 web apps). jQuery and Prototype are the top choices, getting 11 and 13 respectively. It's interesting to note that Dojo is not even featured on this list, though if you [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://royal.pingdom.com/?p=305">Pingdom has complied a list</a> of the Javascript frameworks used by the top sites on the web (top 100 in Alexa US, Webware's top 100 web apps). jQuery and Prototype are the top choices, getting 11 and 13 respectively. </p>
<p>It's interesting to note that Dojo is not even featured on this list, though if you check the comments you'll see that it is used partially at the apple site (in the apple store). This makes me wonder even more regarding Zend's latest decision to <a href="http://weierophinney.net/matthew/archives/176-Zend-Framework-Dojo-Integration.html">integrate Dojo into their framework</a>. As I commented in that release statement (comment #6 is mine), I feel that Dojo isn't appropriate as the default for the framework as it is more complex and much less documented than the other top frameworks. </p>
<p>As a long time jQuery developer I have no intentions of integrating a new Javascript library into my development environment, so I'm obviously biased. I still feel as though Zend missed an opportunity here to better cater to the needs of a broader user base and instead chose to prioritize its partners best interests.</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=68" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="jQuery and Prototype the choice of top websites" data-url="http://www.techfounder.net/2008/06/14/jquery-and-prototype-the-choice-of-top-websites/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/06/14/jquery-and-prototype-the-choice-of-top-websites/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Semi-colon mystery explained, jQuery UI released</title>
		<link>http://www.techfounder.net/2008/06/11/semi-colon-mystery-explained-jquery-ui-released/</link>
		<comments>http://www.techfounder.net/2008/06/11/semi-colon-mystery-explained-jquery-ui-released/#comments</comments>
		<pubDate>Wed, 11 Jun 2008 01:33:50 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=65</guid>
		<description><![CDATA[Javascript is a very mysterious language. Its prototypical inheritance structure and its function == object == function concepts are quite different compared to standard OO languages. As I did with PHP, I try my best to learn best good practices by studying frameworks I like, and in Javascript's case that would be jQuery. I had [...]]]></description>
			<content:encoded><![CDATA[<p>Javascript is a very mysterious language. Its <a title="Wikipedia: Prototypical Inheritance" href="http://en.wikipedia.org/wiki/Prototype-based_programming" target="_blank">prototypical inheritance</a> structure and its function == object == function concepts are quite different compared to standard OO languages. As I did with PHP, I try my best to learn <span style="text-decoration: line-through;">best</span> good practices by studying frameworks I like, and in Javascript's case that would be <a title="jQuery" href="http://jquery.com" target="_blank">jQuery</a>.</p>
<p>I had believed I figured out most of the conventions used in the jQuery source code, however a recent addition has been bugging me and I could not find a reasonable explanation for it - I'm talking about the mysterious semi-colons appearing at the beginning of some of the source files in the library. What is its purpose? Does it make the closure invisible to giant robots from outer space? I had no leads to go on.</p>
<p><a title="jQuery Rule 1.0 released" href="http://flesler.blogspot.com/2008/01/jqueryrule-10-released.html" target="_blank">This blog post</a> by the jQuery.rule team however, reveals the truth about the semi-colon debacle - apparently they're used for safe file concatenation (string join). Well that's a load off my chest. You learn something new every day.</p>
<p>In related news, jQuery UI 1.5 has been officially released, says the <a title="jQuery 1.5 released" href="http://jquery.com/blog/2008/06/09/jquery-ui-v15-released-focus-on-consistent-api-and-effects/" target="_blank">jQuery enquirer</a>. jQuery 1.5 is an extensive UI oriented extension to jQuery, and version 1.5 bring forth many improvements such as a tighter API, an effects library called enchant, a skinning mechanism and plenty of bug fixes. I'm just excited they finally updated their <a title="jQuery UI documentation" href="http://docs.jquery.com/UI" target="_blank">documentation</a>, as I've been using it for a while going only by source code.</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=65" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Semi-colon mystery explained, jQuery UI released" data-url="http://www.techfounder.net/2008/06/11/semi-colon-mystery-explained-jquery-ui-released/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/06/11/semi-colon-mystery-explained-jquery-ui-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pagination with Zend_Db_Select</title>
		<link>http://www.techfounder.net/2008/06/11/pagination-with-zend_db_select/</link>
		<comments>http://www.techfounder.net/2008/06/11/pagination-with-zend_db_select/#comments</comments>
		<pubDate>Wed, 11 Jun 2008 01:02:39 +0000</pubDate>
		<dc:creator>Eran Galperin</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web development]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[pagination]]></category>
		<category><![CDATA[zend_db_select]]></category>

		<guid isPermaLink="false">http://www.techfounder.net/?p=63</guid>
		<description><![CDATA[A common (web) interface feature is to divide a long list of items into numbered pages, a technique called pagination. I'll describe in brief some shortcuts I use with Zend_Db_Select to retrieve the row count and calculate the number of pages for complicated queries. Pagination of long database result sets is done by retrieving a [...]]]></description>
			<content:encoded><![CDATA[<p><img class="header" src="http://www.techfounder.net/wp-content/uploads/2008/06/pages.gif" alt="Pages, by google" />A common (web) interface feature is to divide a long list of items into numbered pages, a technique called <a title="Wikipedia: Pagination" href="http://en.wikipedia.org/wiki/Pagination" target="_blank">pagination</a>. I'll describe in brief some shortcuts I use with Zend_Db_Select to retrieve the row count and calculate the number of pages for complicated queries.<br />
<span id="more-63"></span><br />
Pagination of long database result sets is done by retrieving a limited number of rows from a specific offset. For example, if we want each page to display 10 rows, the offset for page 3 would be 21 (page 1 contains rows 1-10, page 2 containts rows 11-20 and so forth. In MySQL, the first row has an offset of 0 (zero), so for the previous example a page 3 in a 10 rows-per-page pagination system would be queried by an offset of 20.</p>
<p>Paginated queries typically look like this:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> * <span style="color: #993333; font-weight: bold;">FROM</span> articles <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">20</span>, <span style="color: #cc66cc;">10</span> //Selecting page <span style="color: #cc66cc;">3</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #993333; font-weight: bold;">TABLE</span> articles <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span> rows per page<span style="color: #66cc66;">&#41;</span></pre>
<p>In order to generate page navigation, we would need to know the number of pages. We count the total rows that our query generates without the limit clause:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> COUNT<span style="color: #66cc66;">&#40;</span>*<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> articles //Count <span style="color: #993333; font-weight: bold;">ALL</span> rows <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #993333; font-weight: bold;">TABLE</span> articles</pre>
<p>And then we can perform simple arithmetics to calculate the number of pages.</p>
<p>It's relatively straightforward when dealing with simple queries, however for complicated queries (with multiple JOIN clauses) it can be quite a chore.</p>
<p>Lets switch to the Zend Framework and compose ourselves a somewhat elaborate query using Zend_Db_Select:</p>
<pre class="php"><span style="color: #0000ff;">$select</span> = <span style="color: #000000; font-weight: bold;">new</span> Zend_Db_Select<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$select</span> -&amp;gt; from<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'pil'</span> =&amp;gt; <span style="color: #ff0000;">'project_item_list'</span><span style="color: #66cc66;">&#41;</span>,<a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'*'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; <a href="http://www.php.net/join"><span style="color: #000066;">join</span></a><span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'pt'</span> =&amp;gt; <span style="color: #ff0000;">'project_tasks'</span><span style="color: #66cc66;">&#41;</span>,<span style="color: #ff0000;">'pt.id=pil.task_id'</span>,<a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'task'</span>,<span style="color: #ff0000;">'ptid'</span> =&amp;gt; <span style="color: #ff0000;">'id'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; <a href="http://www.php.net/join"><span style="color: #000066;">join</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'projects'</span>,<span style="color: #ff0000;">'projects.id=pt.project_id'</span>,<a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; <a href="http://www.php.net/join"><span style="color: #000066;">join</span></a><span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'ptu'</span> =&amp;gt; <span style="color: #ff0000;">'projects_to_users'</span><span style="color: #66cc66;">&#41;</span>,<span style="color: #ff0000;">'ptu.project_id=projects.id'</span>,<a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; <a href="http://www.php.net/join"><span style="color: #000066;">join</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'users'</span>,<span style="color: #ff0000;">'users.id=pil.assigned_to'</span>,<a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'assignee'</span> =&amp;gt; <span style="color: #ff0000;">'name'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; where<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;pt.project_id='&quot;</span> . <span style="color: #0000ff;">$projectId</span> . <span style="color: #ff0000;">&quot;'&quot;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; where<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;ptu.user_id='&quot;</span> . <span style="color: #0000ff;">$userId</span> . <span style="color: #ff0000;">&quot;'&quot;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; where<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;task_id='&quot;</span> . <span style="color: #0000ff;">$taskId</span> . <span style="color: #ff0000;">&quot;'&quot;</span><span style="color: #66cc66;">&#41;</span>;
	-&amp;gt; where<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;pil.assigned_to='&quot;</span> . <span style="color: #0000ff;">$assignedTo</span> . <span style="color: #ff0000;">&quot;'&quot;</span><span style="color: #66cc66;">&#41;</span>
	-&amp;gt; limitPage<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">3</span>,<span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span>;</pre>
<p>Plenty of JOIN goodness. You'll notice the limitPage() call at the end, which is a nice Zend_Db_Select helper to add a limit clause by a page number (in this case it means limit by page 3, 10 rows per page).</p>
<p>So how do we count the number of rows? We'd want to have a COUNT() function returned from the base table (the one that appears at the from clause), however if we mix that with other columns, we'd have to use GROUP BY which would mess up our result-set.</p>
<p>There are two ways to handle this - generating a similar query sans the columns and the limit clauses, or using the SQL_CALC_FOUND_ROWS() function. The first approach results in two seperate queries while the second is just one query, however it is not that obvious which <a href="http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/">one is better for performance</a>. For our case we'll use the first method, duplicating the original query while stripping out whats needed.</p>
<p>We could recompose the entire query using copy-paste methods, removing the columns and the limit clauses, but we would like a more general solution. I extend Zend_Db_Select and add a simple utility method:</p>
<pre class="php"><span style="color: #000000; font-weight: bold;">class</span> Techfounder_Db_Select <span style="color: #000000; font-weight: bold;">extends</span> Zend_Db_Select <span style="color: #66cc66;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> prepareForCount<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$countColName</span> = <span style="color: #ff0000;">'count'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
		<span style="color: #0000ff;">$this</span> -&amp;gt; <a href="http://www.php.net/reset"><span style="color: #000066;">reset</span></a><span style="color: #66cc66;">&#40;</span>Zend_Db_Select::<span style="color: #006600;">COLUMNS</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #0000ff;">$this</span> -&amp;gt; <a href="http://www.php.net/reset"><span style="color: #000066;">reset</span></a><span style="color: #66cc66;">&#40;</span>Zend_Db_Select::<span style="color: #006600;">LIMIT_COUNT</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #0000ff;">$this</span> -&amp;gt; <a href="http://www.php.net/reset"><span style="color: #000066;">reset</span></a><span style="color: #66cc66;">&#40;</span>Zend_Db_Select::<span style="color: #006600;">LIMIT_OFFSET</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #0000ff;">$table</span> = <a href="http://www.php.net/key"><span style="color: #000066;">key</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span> -&amp;gt; _parts<span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'from'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;
		<span style="color: #0000ff;">$this</span> -&amp;gt; _parts<span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'columns'</span><span style="color: #66cc66;">&#93;</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span>
			<span style="color: #cc66cc;">0</span> =&amp;gt; <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span>
				<span style="color: #cc66cc;">0</span> =&amp;gt; <span style="color: #0000ff;">$table</span>,
				<span style="color: #cc66cc;">1</span> =&amp;gt; <span style="color: #000000; font-weight: bold;">new</span> Zend_Db_Expr<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'COUNT(*)'</span><span style="color: #66cc66;">&#41;</span>,
				<span style="color: #cc66cc;">2</span> =&amp;gt; <span style="color: #0000ff;">$countColName</span>
			<span style="color: #66cc66;">&#41;</span>
		<span style="color: #66cc66;">&#41;</span>;
		<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$this</span>;
	<span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre>
<p>The prepareForCount() method modifies a select object to strip all previously set columns and LIMIT clauses, and to set a COUNT() function on the base table in the query (the row count is returned as a key named 'count'). We can now use this Select class to do the following:</p>
<pre class="php"><span style="color: #0000ff;">$select</span> = <span style="color: #000000; font-weight: bold;">new</span> Techfounder_Db_Select<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
... <span style="color: #808080; font-style: italic;">//Multiple JOIN query, as composed previously</span>
&nbsp;
<span style="color: #0000ff;">$countSelect</span> = clone <span style="color: #0000ff;">$select</span>;
<span style="color: #0000ff;">$countSelect</span> -&amp;gt; prepareForCount<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$result</span> = <span style="color: #0000ff;">$db</span> -&amp;gt; fetchRow<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$countSelect</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">//$db is an instance of Zend_Db_Adapter</span>
<span style="color: #0000ff;">$pageCount</span> = <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>int<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$result</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'count'</span><span style="color: #66cc66;">&#93;</span> - <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> / <span style="color: #0000ff;">$rowCount</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> + <span style="color: #cc66cc;">1</span>; <span style="color: #808080; font-style: italic;">//Using the number of rows to calculate the number of pages.</span>
<span style="color: #808080; font-style: italic;">//$rowCount is the number of rows per page</span></pre>
<p>I go even a step further, and encapsulate this short process in a countPages() method in a custom wrapper for Zend_Db_Select (called Zend_Db_Gateway, for which <a href="http://framework.zend.com/wiki/display/ZFPROP/Zend_Db_Gateway">I submitted a proposal</a> and would talk about in my conclusion to my Models in the Zend Framework series).</p>
 <img src="http://www.techfounder.net/wp-content/plugins/feed-statistics.php?view=1&post_id=63" width="1" height="1" style="display: none;" />
	<div style="">
		<a href="http://twitter.com/share" class="twitter-share-button" data-count="vertical" data-text="Pagination with Zend_Db_Select" data-url="http://www.techfounder.net/2008/06/11/pagination-with-zend_db_select/"  data-via="erangalperin">Tweet</a>
	</div>
	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>]]></content:encoded>
			<wfw:commentRss>http://www.techfounder.net/2008/06/11/pagination-with-zend_db_select/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

