<?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>Programmer&#039;s Notes &#187; DB Design</title>
	<atom:link href="http://programmersnotes.info/category/databases/db-design/feed/" rel="self" type="application/rss+xml" />
	<link>http://programmersnotes.info</link>
	<description>Notes on the web-development and artificial intelligence.</description>
	<lastBuildDate>Mon, 18 Jul 2011 13:20:46 +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>Database structure and filtering approach. SMS Notification system.</title>
		<link>http://programmersnotes.info/2010/03/19/database-sms-notification/</link>
		<comments>http://programmersnotes.info/2010/03/19/database-sms-notification/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 06:00:38 +0000</pubDate>
		<dc:creator>Konstantin Mirin</dc:creator>
				<category><![CDATA[DB Design]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[database design]]></category>
		<category><![CDATA[modelling]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sms-notify]]></category>
		<category><![CDATA[UML]]></category>

		<guid isPermaLink="false">http://programmersnotes.info/?p=351</guid>
		<description><![CDATA[The database structure In the previous post I outlined the system&#8217;s specs and use cases. We also selected the primary use case we should start from – that is filtering screen. The complexity with DB design here is that we want maximum flexibility on the one hand and we don&#8217;t want to lose much in [...]


No related posts.

Related posts brought to you by <a href='http://yarpp.org'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<h2><a name="dbstruct">The database structure</a></h2>
<p>In the <a href="http://programmersnotes.info/2010/03/18/requirements-use-cases-sms-notification/">previous post</a> I outlined the system&#8217;s specs and use cases. We also selected the primary use case we should start from – that is <a href="http://programmersnotes.info/2010/03/18/requirements-use-cases-sms-notification/#groupadmin">filtering screen</a>.</p>
<p><span id="more-351"></span></p>
<p>The complexity with DB design here is that we want maximum flexibility on the one hand and we don&#8217;t want to lose much in performance on the other hand.<br />
Let&#8217;s recap what data about student we should store:</p>
<ol>
<li>Phone</li>
<li>Password</li>
<li>Email</li>
<li>ICQ</li>
<li>Name</li>
<li>Surname</li>
<li>Patronymic</li>
<li>Gender</li>
<li>Birthday</li>
<li>Faculty</li>
<li>Course</li>
<li>Group</li>
<li>Clubs</li>
<li>Tags</li>
<li>OK to send SMS (true/false)</li>
</ol>
<p>Items 1-9 and #15 are scalar values and can be easily stored in User table as fields of the correspondent type. While Faculty, Course, Group and Clubs are either N-M (Clubs) or 1-N relations. So obvious way to handle them is to create tables and cross-table for N-M relation. Tags can be also represented as N-M relation.<br />
It seems OK until we don&#8217;t want to extend the system by adding some more fields. But even without extensibility in mind, we should create 3 separate tables (for courses, faculties and clubs). However if we look closer at these, we&#8217;ll see that all of them are kind of groups and we can create a kind of hierarchy:</p>
<ul>
<li>University
<ul>
<li>Faculty
<ul>
<li>Course
<ul>
<li>Group</li>
</ul>
</li>
</ul>
</li>
<li>Club
<ul>
<li>Section</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>So we can consider everything to be group. With this approach we also store information about relations between these groups.<br />
With such approach we can add more types of groups in the future if needed. Or this solution can be ported to another domain model (e.g. school or business organization) without changes in the structure. We should only define, which groups are required for user. In this case Faculty, course and group are required. However, knowing the group, we can get both course and faculty. But I&#8217;m not sure if that is a good idea because this way we&#8217;ll have to make several queries to the DB in order to get faculty instead of one.<br />
Here&#8217;s the DB scheme we came up with:</p>
<div id="attachment_360" class="wp-caption aligncenter" style="width: 566px"><a href="http://programmersnotes.info/wp-content/uploads/2010/03/db.png"><img src="http://programmersnotes.info/wp-content/uploads/2010/03/db.png" alt="Database design" title="Database design" width="556" height="349" class="size-full wp-image-360" /></a><p class="wp-caption-text">Database design</p></div>
<h2><a name="filtering">Filtering it</a></h2>
<p>Let&#8217;s try to compose some simple queries to test if our DB can cope with them.</p>
<ol>
<li>Let&#8217;s get all male users who&#8217;re elder than 18:
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> User <span class="kw1">WHERE</span> gender=<span class="st0">&#8216;male&#8217;</span> <span class="kw1">AND</span> birthday &lt;= <span class="st0">&#8217;1992-03-19 23:59:59&#8242;</span></div>
</li>
</ol>
</div>
<p>Date for the birthday is set to the 18 years back from now. Everyone who was born before or on 19 of March 1992 will fall into the condition. And gender is obvious.</li>
<li>Let&#8217;s try to get all male that have first names starting with &#8216;K&#8217; and who study on the first or second course:
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> u.* <span class="kw1">FROM</span> User u <span class="kw1">INNER</span> <span class="kw1">JOIN</span> UserGroup ug <span class="kw1">ON</span> u.userID=ug.userID <span class="kw1">WHERE</span> u.gender=<span class="st0">&#8216;male&#8217;</span> <span class="kw1">AND</span> u.name <span class="kw1">LIKE</span> <span class="st0">&#8216;K%&#8217;</span> <span class="kw1">AND</span> ug.groupID <span class="kw1">IN</span> <span class="br0">&#40;</span><span class="nu0">5</span>,<span class="nu0">6</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Suppose that in Group table we have groups for the first course and second course and they have Ids 5 and 6 respectively.</li>
<li>Let&#8217;s try to search for all who is on the 3rd course and is also in Geeks&#8217; Club:
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> u.* <span class="kw1">FROM</span> User u <span class="kw1">INNER</span> <span class="kw1">JOIN</span> UserGroup ug <span class="kw1">ON</span> u.userID=ug.userID <span class="kw1">WHERE</span> ug.groupID <span class="kw1">IN</span> <span class="br0">&#40;</span><span class="nu0">7</span>, <span class="nu0">15</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>7 is ID of the group “3rd course” and 15 is ID of the group “Geeks&#8217; Club”.<br />
We have the problem with the last query <img src='http://programmersnotes.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  It will find all users who either studies on the 3rd course or attends Geeks&#8217; Club. However we need 3rd course and Geeks&#8217; club.<br />
There are two possible solutions here. One is SQL-based, another is PHP-based.</p>
<ol>
<li>1.SQL-based:
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> User <span class="kw1">WHERE</span> userID <span class="kw1">IN</span> <span class="br0">&#40;</span><span class="kw1">SELECT</span> userID <span class="kw1">FROM</span> UserGroup <span class="kw1">WHERE</span> userID <span class="kw1">IN</span><span class="br0">&#40;</span><span class="kw1">SELECT</span> userID <span class="kw1">FROM</span> UserGroup <span class="kw1">WHERE</span> groupID=<span class="nu0">15</span><span class="br0">&#41;</span> <span class="kw1">AND</span> groupID=<span class="nu0">7</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Here we select users who have group=15. Then from these users we select the ones who have group=7 as well, and finally we select user records that correspond the userIDs found.<br />
I think, the variant with INNER JOIN is also possible here (at least, joining results of the groups filtering instead of sub-querying). It just takes some time to figure it out and it has to deal more with optimization than with the principle of filtering.<br />
Anyway, the more groups we have here, the more complex this query becomes.<br />
<strong>UPDATE:</strong> <a href="http://www.sitepoint.com/forums/showthread.php?p=4542692">Here</a> I&#8217;ve been advised to use the following query which is more simple and efficient:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; u.*</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">FROM</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; USER u</div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">INNER</span> <span class="kw1">JOIN</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; UserGroup ug1</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; u.id = ug1.userID <span class="kw1">AND</span> ug1.groupID=<span class="nu0">7</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">INNER</span> <span class="kw1">JOIN</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; UserGroup ug2</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; u.id = ug2.userID <span class="kw1">AND</span> ug2.groupID=<span class="nu0">15</span></div>
</li>
</ol>
</div>
<p>I think this is the best way of making such queries. Great thanks to <strong>ScallioXTX</strong></li>
<li>PHP-based. Basically, the principle is the same:
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$group7</span> = getUsersForGroup<span class="br0">&#40;</span><span class="nu0">7</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$group15</span> = getUsersForGroup<span class="br0">&#40;</span><span class="nu0">15</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$userIDs</span> = <a href="http://www.php.net/array_intersect"><span class="kw3">array_intersect</span></a><span class="br0">&#40;</span><span class="re0">$group7</span>, <span class="re0">$group15</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$users</span> = getUsersByIDs<span class="br0">&#40;</span><span class="re0">$userIDs</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>getUsersForGroup actually executes the query:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> userID <span class="kw1">FROM</span> UserGroup <span class="kw1">WHERE</span> groupID=<span class="br0">&#91;</span><span class="kw1">GROUP</span><span class="br0">&#93;</span></div>
</li>
</ol>
</div>
<p>getUsersByID executes the following query:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> User <span class="kw1">WHERE</span> userID <span class="kw1">IN</span> <span class="br0">&#40;</span><span class="br0">&#91;</span>ids<span class="br0">&#93;</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>array_intersect is a PHP function that returns the values present in all given arrays, returns the intersection of sets.<br />
For example, if we give it 3 arrays:<br />
(1, 5, 8, 15)<br />
(5, 8, 15, 19)<br />
(1, 5, 15, 25)<br />
it will return (5, 15).<br />
In this case we execute several little queries instead of one big. In MySQL this often gives benefits in performance.</li>
</ol>
</li>
</ol>
<p>So that&#8217;s our filtering approach.</p>
<p>There is one thing to add here. If we have group #1 and #2 and group#2 is a child of #1. And user selected to filter users which are both in #1 and #2, then we should perform a little optimization and search only for #2 because that will be the correct answer to the query. This situation is stupid, but we should act smart even in a stupid queries <img src='http://programmersnotes.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Maybe there are better solutions. We&#8217;re open to them! Moreover, we realize that there are more experienced developers that already solved such problem. Help us <img src='http://programmersnotes.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Tomorrow we have a meeting where we&#8217;ll be discussing the architecture, classes etc. I&#8217;ll upload our results on the weekends or early next week. This depends on the amount of work done during the meeting.<br />
Stay tuned! Subscribe to my blog&#8217;s RSS, share your opinions/suggestions in comments and don&#8217;t miss the next post in this series!</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a title="Click me to see the sites." href="#" onclick="$$('div.d351').each( function(e) { e.visualEffect('slide_down',{duration:2.5}) }); return false;"><strong><em>Liked the post? Bookmark it</em></strong></a>
<br />
<div class="d351" style="overflow:hidden">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;title=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;title=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;title=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;T=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;title=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;Slashdot"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/slashdot.png" title="Add to&nbsp;Slashdot" alt="Add to&nbsp;Slashdot" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;title=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Database+structure+and+filtering+approach.+SMS+Notification+system.+@+http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fprogrammersnotes.info%2F2010%2F03%2F19%2Fdatabase-sms-notification%2F&amp;t=Database+structure+and+filtering+approach.+SMS+Notification+system." rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
<a style="font-size:90%;text-align: right; " title="Click me to hide the sites." href="#" onclick="$$('div.d351').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); return false;">Hide Sites</a>
</div>
</div>
<!-- Social Bookmarks END -->
<script type="text/javascript">$$('div.d351').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); </script>

<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://yarpp.org'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://programmersnotes.info/2010/03/19/database-sms-notification/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building high-loaded portal &#8211; InnoDB vs MyISAM</title>
		<link>http://programmersnotes.info/2009/05/20/building-high-loaded-portal-innodb-vs-myisam/</link>
		<comments>http://programmersnotes.info/2009/05/20/building-high-loaded-portal-innodb-vs-myisam/#comments</comments>
		<pubDate>Wed, 20 May 2009 07:00:55 +0000</pubDate>
		<dc:creator>Konstantin Mirin</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[DB Design]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[DB]]></category>
		<category><![CDATA[design pattern]]></category>
		<category><![CDATA[efficiency]]></category>
		<category><![CDATA[production]]></category>

		<guid isPermaLink="false">http://konstantin.takeforce.net/?p=5</guid>
		<description><![CDATA[Post shares practical experience of developing MySQL DB for the high-loaded website.


No related posts.

Related posts brought to you by <a href='http://yarpp.org'>Yet Another Related Posts Plugin</a>.]]></description>
			<content:encoded><![CDATA[<h2><a name="intro">Preface</a></h2>
<p>In November 2008 I&#8217;ve got a nice project, that resulted in a complex search engine, that specializes in clothing. I can&#8217;t give the link now, but will do when site officially launches. Key features of such service are:</p>
<ul>
<li>Large number of users, which search with various parameters, rate items, leave comments, create articles etc.</li>
<li>Large database, that is updated frequently</li>
</ul>
<p>Sure, the site is running on a dedicated server, sure I use caching, but optimal DB is a key to success.</p>
<p><span id="more-5"></span></p>
<h2><a name="myisam-innodb">MyISAM or InnoDB?</a></h2>
<p>Since we need reliability, I created different tests, search the internet etc. My main question was &#8211; what to use MyISAM or InnoDB? I found the <a href="http://www.mysqlperformanceblog.com/2007/01/08/innodb-vs-myisam-vs-falcon-benchmarks-part-1/">post on the MySQL Perfomance Blog</a> (also <a href="http://www.mysqlperformanceblog.com/2007/10/12/myisam-scalability-and-innodb-falcon-benchmarks/">this</a> and <a href="http://www.mysqlperformanceblog.com/2007/01/03/innodb-benchmarks/">this</a>) and came to the conclusion, that when SELECT&#8217;ing, InnoDB is definitely faster (or, at least, is not slower). In addition, it provides constraints mechanism and allows transactions. The only thing it doesn&#8217;t have is FULLTEXT search. One more disadvantage is slower inserts. However, 80% of DB usage in this project are SELECT queries without FULLTEXT. For the fulltext search I created MyISAM table with fields I need and it works fine. The project is finished, but there will be phase 2 and I&#8217;m thinking of introducing <a href="http://www.sphinxsearch.com/">Sphinx</a> there. Anybody has experience with it?<br />
So I came up with InnoDB storage engine.</p>
<h2><a name="structure">Optimizing structure</a></h2>
<p>Next important step is DB structure. I&#8217;ll give some background info about the project so you could better understand what I&#8217;m talking about. The site collects info from different UK shops. Then users can rate them, add some tags, create articles (called &#8220;looks&#8221;) and link that articles to the products they&#8217;re writing about. And the same (tags, comments, rating) applies to the looks. Here we come across with an interesting question. We can create structure of different types for this:</p>
<ul>
<li>Create 2 separate cross-tables for linking Rating to Look or Product</li>
<li>Create one cross-table and add additional field &#8220;type&#8221; there to differentiate between Product and Look entities</li>
</ul>
<p>See both variants in the following images:<br />
<div id="attachment_251" class="wp-caption aligncenter" style="width: 310px"><a href="http://programmersnotes.info/wp-content/uploads/2009/05/norm1.png"><img src="http://programmersnotes.info/wp-content/uploads/2009/05/norm-300x174.png" alt="Normalized variant" title="Normalized variant" width="300" height="174" class="size-medium wp-image-251" /></a><p class="wp-caption-text">Normalized variant</p></div><br />
<div id="attachment_252" class="wp-caption aligncenter" style="width: 310px"><a href="http://programmersnotes.info/wp-content/uploads/2009/05/denorm1.png"><img src="http://programmersnotes.info/wp-content/uploads/2009/05/denorm-300x157.png" alt="Denormalized version" title="Denormalized version" width="300" height="157" class="size-medium wp-image-252" /></a><p class="wp-caption-text">Denormalized version</p></div><br />
Initially I thought that the second variant would perform better, but after creating and running tests, I saw, that:</p>
<ul>
<li>If there are 0-2 ratings linked to entity, then normalized variant is better</li>
<li>If there are 3-5 ratings linked to entity, then denormalized variant is slightly (less than 1%) better</li>
<li>If there are 6-8 ratings linked to the entity, the normalized variant wins again</li>
</ul>
<p>I did these tests for different situations similar to this one, in each test I generated random records and randomly linked them with each other. Number of record in Product, Look tables was 10000, in Rating &#8211; 20000. Number of records in cross tables varies because the linkings are random.<br />
So I came up with normalizing everything like it should be done according to the DB theory.</p>
<p>The only exclusion of this rule is the following situation. In this project you can add different alternatives to the product. Each alternative is &#8220;better&#8221; or &#8220;cheaper&#8221; or &#8220;different&#8221; etc. And since the only case when these alternatives are pulled from DB is when user views the product, they are pulled altogether, so it is better to keep them in the same table.</p>
<h2><a name="conclusion">Conclusion</a></h2>
<ul>
<li>InnoDB turns out to behave better under the high load, it supports transactions and maintains constraints. All that helps to develop better and never leave orphan records.</li>
<li>Using normalization techniques you usually get better performance</li>
<li>Create tests and test everything if you are going to do something great <img src='http://programmersnotes.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<h4>Further reading</h4>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Database_normalization">Database Normalization</a></li>
<li><a href="http://www.mysqlperformanceblog.com/2007/01/08/innodb-vs-myisam-vs-falcon-benchmarks-part-1/">MySQL Performance Blog</a></li>
</ul>
<p>P.S. I&#8217;m looking forward to see your comments on implementation techniques in the high-loaded websites, your thoughts about the InnoDB vs MyISAM question and anything else you can think of <img src='http://programmersnotes.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a title="Click me to see the sites." href="#" onclick="$$('div.d5').each( function(e) { e.visualEffect('slide_down',{duration:2.5}) }); return false;"><strong><em>Liked the post? Bookmark it</em></strong></a>
<br />
<div class="d5" style="overflow:hidden">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;title=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;title=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;title=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;T=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;title=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;Slashdot"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/slashdot.png" title="Add to&nbsp;Slashdot" alt="Add to&nbsp;Slashdot" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;title=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM+@+http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fprogrammersnotes.info%2F2009%2F05%2F20%2Fbuilding-high-loaded-portal-innodb-vs-myisam%2F&amp;t=Building+high-loaded+portal+%26%238211%3B+InnoDB+vs+MyISAM" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://programmersnotes.info/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
<a style="font-size:90%;text-align: right; " title="Click me to hide the sites." href="#" onclick="$$('div.d5').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); return false;">Hide Sites</a>
</div>
</div>
<!-- Social Bookmarks END -->
<script type="text/javascript">$$('div.d5').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); </script>

<p>No related posts.</p>
<p>Related posts brought to you by <a href='http://yarpp.org'>Yet Another Related Posts Plugin</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://programmersnotes.info/2009/05/20/building-high-loaded-portal-innodb-vs-myisam/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

