<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9152889102684049863</id><updated>2012-02-12T00:12:19.068-07:00</updated><category term='Reviews'/><category term='Cell Phones'/><category term='Best Practice'/><category term='mysql logging'/><category term='How-To'/><category term='network'/><category term='mysql connection'/><category term='packet timeout'/><category term='None'/><category term='MySQL Certification'/><category term='Administration'/><title type='text'>K Benton CMDBA</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-1291815483170316371</id><published>2012-02-12T00:12:00.000-07:00</published><updated>2012-02-12T00:12:19.077-07:00</updated><title type='text'>A basic shared-nothing data sharding system</title><content type='html'>There's a lot of buzz about sharding data. Today, I'll provide a very brief overview of how sharding helps systems I manage run more efficiently and how we're addressing keeping individual shards balanced.&lt;br /&gt;&lt;br /&gt;The goal of sharding data in our environment involves: 1) make the structure of the data consistent across all the shards, 2) dividing data up so it can be found easily, 3) automatically and continuously re-balance the shards, and 4) allow for changes in scale (like adding a new shard or different shard sizes).&lt;br /&gt;&lt;br /&gt;Item 1 is a snap - all we do there is to deploy the same data structures in each of the shards with all the supporting data required to answer questions related to a user. Some of this data is user-specific, some is globally replicated. In any case, this goal makes it easy to use one set of code to access data in any of the shards without having to cross to another shard or database to get the answer for a question. This reduces workload in the application and on other database servers.&lt;br /&gt;&lt;br /&gt;Item 2 is done by hashing our key data. Let's say that we have a set of widgets that users are concerned with. Some users have a few widgets, some have a lot, but each user is very different from another. Widgets are pretty common and well defined. Each user has a user ID and any question we ask the system always involves a specific user ID. So - our key data we hash against in this case would be the user ID. Data about the widgets is replicated to all the shards, but data about each user is only kept on the shard where that user's data lives.&lt;br /&gt;&lt;br /&gt;Item 3 is handled by a separate process that utilizes the same API the application uses. Balancing the data between shards is simple - the balancer asks the API if there are any users that need to move. If yes, the balancer lets the API know to lock that user temporarily, moves the data, then unlocks the users for use on the new shard. What this means for applications is each time a location is returned for a specific user, that location is only guaranteed for a given window of time (30 seconds for example). So - when the balancer tells the API it's moving a user's records, any requests for that user's records are held up until the user's data is moved. The API is smart enough to only let the balancer move data that has not been accessed recently. This doesn't prevent all lock collisions, but it handles most of them.&lt;br /&gt;&lt;br /&gt;Item 4 is handled through the configuration of the API. Because we use an API to tell the application where the data is for a given user, we've abstracted away where data actually lives. This makes it easy to add and remove servers from the sharding pool. We've extended this to include allowing a shard to be marked as in a draining state. When a shard is draining, the API will ask the balancer to move rows from the draining shard and redistribute that information onto other members of the sharding pool. This makes it possible to take a shard out of rotation for routine maintenance without the loss of data.&lt;br /&gt;&lt;br /&gt;Notice that I didn't mention any specific software here. I didn't tell you what language the application is written in, what language the API is written in, or what the actual data store was. The technique of sharding data is pretty simple and can be done with nearly any persistence layer using any programming language.&lt;br /&gt;&lt;br /&gt;The beauty of this system is that once the API is written, the balancer can be a complete "black box" to the application. This type of system could be implemented with a data store when just starting out and be expanded to multiple stores as the need expands. Also - sharding key needs to change, again, the application doesn't need to change - just the API and the balancer.&lt;br /&gt;&lt;br /&gt;One other big benefit to sharding data like this - it's often a lot cheaper to buy several smaller systems than to buy and maintain one very large system. If one of the systems in the sharding pool goes off-line, the worst possible exposure in a shared-nothing sharding system is the data stored on the member that went down. In a monolithic system, you stand to lose a lot more.&lt;br /&gt;&lt;br /&gt;While I wouldn't suggest trying to do this type of work on top of every data set out there, I do see that there is a lot of benefit when the types of questions being asked of a data set can be divided up easily while still making it relatively easy to answer the "question at hand" from a single source. The secret in the sauce is making sure that any common data is shared among all the systems in the pool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-1291815483170316371?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/1291815483170316371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2012/02/basic-shared-nothing-data-sharding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/1291815483170316371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/1291815483170316371'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2012/02/basic-shared-nothing-data-sharding.html' title='A basic shared-nothing data sharding system'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-5132612377573964614</id><published>2012-01-15T18:44:00.000-07:00</published><updated>2012-01-15T18:44:17.760-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Managing incoming emails</title><content type='html'>Reading emails all day long tends to be very counter-productive for me. I usually end up responding faster than anyone else which generally gets me a lot more work than I need. At the same time, I have a responsibility during my times as primary and secondary on-call to respond within our service level agreement. So - how do I find balance? My team and I use mailing lists to help us manage those truly urgent issues versus those issues that can be handled as time allows. We have three lists:&lt;br /&gt;&lt;br /&gt;group_primary@foo.com&lt;br /&gt;group_secondary@foo.com&lt;br /&gt;group_admin@foo.com&lt;br /&gt;&lt;br /&gt;We've published these three lists to our operations center. Everyone else just gets the admin list. We don't tell others about the primary and secondary lists because anything we'd get on primary or secondary would need to come via the operations center anyway. We also don't want our over 600 co-workers (not on our team and not in the NOC) to email us willy-nilly using our on-call emails.&lt;br /&gt;&lt;br /&gt;Next, on each of our team's smart phones, we've set them up to recognize emails going specifically to the primary and secondary emails so our phones will either go off like a pager or (in my case) read the sender and destination email (think "Inbound Primary email from the NOC"). That prevents me from having to look at my phone every time a new message comes in but lets me know when there's something that requires my attention.&lt;br /&gt;&lt;br /&gt;The other thing we do is to make it easy to change the destination for the primary address easily so that only primary gets notified. Secondary is notified in the same way but on my two-man team, there are only two of us so secondary always goes to the whole team (for now).&lt;br /&gt;&lt;br /&gt;Finally, to help us have reasonable sanity, I do what I can to only check the "other" emails twice a day.&lt;br /&gt;&lt;br /&gt;The &amp;nbsp;net result of this process is I am able to focus on getting project work done between routine email readings and it lets others figure things out for themselves or wait a bit for an answer. If it was truly urgent, the sender could simply ask the NOC to reach out to the on-call person to get a faster response.&lt;br /&gt;&lt;br /&gt;How do you deal with your on-call processes and email?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-5132612377573964614?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/5132612377573964614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2012/01/managing-incoming-emails.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/5132612377573964614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/5132612377573964614'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2012/01/managing-incoming-emails.html' title='Managing incoming emails'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-6745918380589911242</id><published>2011-11-28T09:20:00.001-07:00</published><updated>2011-11-28T09:28:46.669-07:00</updated><title type='text'>Watch this video for instructions on how to use indexes better</title><content type='html'>This is the first video I've ever seen that visually represents how indexing works. I've seen good stuff before but this ... wow. Yes - it has some stuff about Tokutek in it, but that's not why I suggest watching it - it's because it makes you re-think how to define good indexes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=AVNjqgf7zNw"&gt;http://www.youtube.com/watch?v=AVNjqgf7zNw&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-6745918380589911242?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.youtube.com/watch?v=AVNjqgf7zNw' title='Watch this video for instructions on how to use indexes better'/><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/6745918380589911242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2011/11/watch-this-video-for-instructions-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6745918380589911242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6745918380589911242'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2011/11/watch-this-video-for-instructions-on.html' title='Watch this video for instructions on how to use indexes better'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-759558355640262211</id><published>2011-11-27T14:58:00.000-07:00</published><updated>2011-11-27T14:58:26.842-07:00</updated><title type='text'>Flashback to summer riding</title><content type='html'>With all the recent crummy weather, I thought I'd resurrect a summer fun photo (from around July 4th, 2011) :-) If you like wind farms and/or motorcycling, you'll like this pic of my 2003 Honda Silverwing:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8zr1sHilCmU/TtKx95zTuaI/AAAAAAAAAB8/eZauFLcDKhI/s1600/Swing.jpg" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="211" width="400" src="http://3.bp.blogspot.com/-8zr1sHilCmU/TtKx95zTuaI/AAAAAAAAAB8/eZauFLcDKhI/s400/Swing.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;For those that are wondering, it gets about 52 MPG normally during the summer and around 45 MPG in the winter and will do over 100MPH.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-759558355640262211?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/759558355640262211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2011/11/flashback-to-summer-riding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/759558355640262211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/759558355640262211'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2011/11/flashback-to-summer-riding.html' title='Flashback to summer riding'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-8zr1sHilCmU/TtKx95zTuaI/AAAAAAAAAB8/eZauFLcDKhI/s72-c/Swing.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-6173008150531470828</id><published>2011-10-20T00:54:00.001-06:00</published><updated>2011-10-20T01:24:05.721-06:00</updated><title type='text'>On-Call Silliness</title><content type='html'>Are you on-call? Do you get called up for stuff that just makes no sense for you to attend to? Check out this video...&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://www.xtranormal.com/watch/12577781/the-frobnicator-wont-frobnicate" target="_new" style="font-size: 14px;font-weight:bold;"&gt;THE FROBNICATOR WON&amp;#39;T FROBNICATE!&lt;/a&gt;&lt;br /&gt;by: &lt;a href="http://www.xtranormal.com/profile/7202203" style="" target="_new"&gt;kbcmdba&lt;/a&gt;&lt;/p&gt;&lt;iframe id="xtranormal_THE FROBNICATOR WON&amp;#39;T FROBNICATE!" name="xtranormal_THE FROBNICATOR WON&amp;#39;T FROBNICATE!" style="width:480px;height:299px;" src="http://www.xtranormal.com/xtraplayr/12577781/the-frobnicator-wont-frobnicate" marginwidth="0" marginheight="0" border="0" frameborder="0" scrolling="auto"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The trick to handling on-call is to make sure that you're getting called when your expertise is really needed. If you're getting called for things you can automate, automate them. If you're getting called for stuff that doesn't apply to you, show them this video. Just because the frobnicator won't frobnicate for someone else, doesn't mean it's your responsibility to fix it or even tell the right person about it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-6173008150531470828?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.xtranormal.com/watch/12577781/the-frobnicator-wont-frobnicate' title='On-Call Silliness'/><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/6173008150531470828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2011/10/on-call-silliness.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6173008150531470828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6173008150531470828'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2011/10/on-call-silliness.html' title='On-Call Silliness'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-3760742096933605660</id><published>2011-06-20T11:22:00.001-06:00</published><updated>2011-06-20T13:41:00.184-06:00</updated><title type='text'>mysqldumpslow and Rows Examined</title><content type='html'>&lt;span style="font-size: small;"&gt;I have found that watching the ratio of rows sent to rows examined helps me get a much better idea of how hard the server has to work to get a result set. Unfortunately, mysqldumpslow in MySQL 5.1 doesn't provide that capability. Rather than keeping it to myself, I'm sharing my fix with the world in hopes that it gets included in all the current and future versions of MySQL. :-)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This patch is officially entered into the public domain.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;--- mysqldumpslow 2010-05-07 10:17:19.000000000 -0500&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+++ mysqldumpslow 2011-06-20 11:46:44.000000000 -0500&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@@ -8,8 +8,8 @@&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;use strict;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;use Getopt::Long;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-# t=time, l=lock time, r=rows&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-# at, al, and ar are the corresponding averages&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+# t=time, l=lock time, r=rows sent, e=rows examined&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+# at, al, ar, and ae are the corresponding averages&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;my %opt = (&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; s =&amp;gt; 'at',&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@@ -83,8 +83,8 @@&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; s/^#? Time: \d{6}\s+\d+:\d+:\d+.*\n//;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($user,$host) = s/^#? User\@Host:\s+(\S+)\s+\@\s+(\S+).*\n// ? ($1,$2) : ('','');&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp; s/^# Query_time: ([0-9.]+)\s+Lock_time: ([0-9.]+)\s+Rows_sent: ([0-9.]+).*\n//;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($t, $l, $r) = ($1, $2, $3);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; s/^# Query_time: ([0-9.]+)\s+Lock_time: ([0-9.]+)\s+Rows_sent: ([0-9.]+)\s+Rows_examined: ([0-9.]+).*\n//;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($t, $l, $r, $e) = ($1, $2, $3, $4);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $t -= $l unless $opt{l};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # remove fluff that mysqld writes to log when it (re)starts:&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@@ -121,6 +121,7 @@&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $s-&amp;gt;{t} += $t;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $s-&amp;gt;{l} += $l;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $s-&amp;gt;{r} += $r;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; $s-&amp;gt;{e} += $e;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $s-&amp;gt;{users}-&amp;gt;{$user}++ if $user;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $s-&amp;gt;{hosts}-&amp;gt;{$host}++ if $host;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@@ -129,10 +130,11 @@&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;foreach (keys %stmt) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my $v = $stmt{$_} || die;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($c, $t, $l, $r) = @{ $v }{qw(c t l r)};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($c, $t, $l, $r, $e) = @{ $v }{qw(c t l r e)};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $v-&amp;gt;{at} = $t / $c;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $v-&amp;gt;{al} = $l / $c;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $v-&amp;gt;{ar} = $r / $c;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; $v-&amp;gt;{ae} = $e / $c;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;}&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;my @sorted = sort { $stmt{$b}-&amp;gt;{$opt{s}} &amp;lt;=&amp;gt; $stmt{$a}-&amp;gt;{$opt{s}} } keys %stmt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@@ -141,13 +143,13 @@&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;foreach (@sorted) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my $v = $stmt{$_} || die;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($c, $t,$at, $l,$al, $r,$ar) = @{ $v }{qw(c t at l al r ar)};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; my ($c, $t,$at, $l,$al, $r,$ar, $e,$ae) = @{ $v }{qw(c t at l al r ar e ae)};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my @users = keys %{$v-&amp;gt;{users}};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my $user&amp;nbsp; = (@users==1) ? $users[0] : sprintf "%dusers",scalar @users;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my @hosts = keys %{$v-&amp;gt;{hosts}};&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; my $host&amp;nbsp; = (@hosts==1) ? $hosts[0] : sprintf "%dhosts",scalar @hosts;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp; printf "Count: %d&amp;nbsp; Time=%.2fs (%ds)&amp;nbsp; Lock=%.2fs (%ds)&amp;nbsp; Rows=%.1f (%d), $user\@$host\n%s\n\n",&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $c, $at,$t, $al,$l, $ar,$r, $_;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp; printf "Count: %d&amp;nbsp; Time=%.2fs (%ds)&amp;nbsp; Lock=%.2fs (%ds)&amp;nbsp; Rows Sent=%.1f (%d) Rows Examined=%.1f (%d), $user\@$host\n%s\n\&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;n",&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $c, $at,$t, $al,$l, $ar,$r, $ae,$e, $_;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;}&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;sub usage {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@@ -163,11 +165,13 @@&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; -v&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; verbose&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; -d&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; debug&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-&amp;nbsp; -s ORDER&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; what to sort by (al, at, ar, c, l, r, t), 'at' is default&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp; -s ORDER&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; what to sort by (ae, al, at, ar, c, e, l, r, t), 'at' is default&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ae: average rows examined&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; al: average lock time&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ar: average rows sent&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at: average query time&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c: count&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;+&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e: rows examined&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; l: lock time&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; r: rows sent&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; t: query time&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-3760742096933605660?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://bugs.mysql.com/bug.php?id=61572' title='mysqldumpslow and Rows Examined'/><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/3760742096933605660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2011/06/mysqldumpslow-and-rows-examined.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3760742096933605660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3760742096933605660'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2011/06/mysqldumpslow-and-rows-examined.html' title='mysqldumpslow and Rows Examined'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-1832407856578326542</id><published>2011-05-28T11:41:00.001-06:00</published><updated>2011-05-28T11:46:56.847-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql logging'/><category scheme='http://www.blogger.com/atom/ns#' term='packet timeout'/><category scheme='http://www.blogger.com/atom/ns#' term='network'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql connection'/><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Heavy improper connection termination creates disk full risk</title><content type='html'>&lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-options.html#option_mysqld_log-warnings"&gt;Logging warnings&lt;/a&gt;,  is generally a good thing for a DBA. Without them, we may not be able to  understand when there are problems that are otherwise hard to find. One of the warnings mysqld logs looks a bit like this:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;110528 11:35:44 [Warning] Aborted connection 4185247 to db: 'db_name' user 'user_name' host: 'a.b.c.com' (Got an error reading communication packets)&lt;/blockquote&gt;There are two primary candidates for this type of warning: a) the client application, or b) the network. &lt;br /&gt;&lt;br /&gt;On the client side, this is often caused by programs that terminate the connection without calling mysql_close after completing use of the connection. This problem is so common, in fact, that it is documented in &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/communication-errors.html"&gt;http://dev.mysql.com/doc/refman/5.5/en/communication-errors.html&lt;/a&gt;&lt;br /&gt;I can't count how many times I've had to speak with developers about making sure they close connections properly in order to prevent this kind of warning from occurring.&lt;br /&gt;&lt;br /&gt;At the root of this issue, mysqld expects to receive some sort of information back from each client every so many (&lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_interactive_timeout"&gt;interactive_timeout&lt;/a&gt; or &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_wait_timeout"&gt;wait_timeout&lt;/a&gt;) seconds. If that time elapses without receiving anything, mysqld assumes that the connection has died. Rather than letting the valuable information go unnoticed, it logs that as a warning. mysql_close() tells mysqld that the connection is closing normally and the server should do its normal cleanup (no need to log normal closures).&lt;br /&gt;&lt;br /&gt;If your code or the library it utilizes on doesn't call mysql_close when your program exits, mysqld will eventually log an error like the one above. If you utilize persistent connections, you will need to make sure that your connection talks to mysqld on a regular basis to keep that connection alive. If your library handles that for you, great. Otherwise, you'll need to "ping" mysqld at least once every &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_interactive_timeout"&gt;interactive_timeout&lt;/a&gt;-1 or &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_wait_timeout"&gt;wait_timeout&lt;/a&gt;-1 seconds depending on your connection type. Most people should use &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_wait_timeout"&gt;wait_timeout&lt;/a&gt; for programs and &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_interactive_timeout"&gt;interactive_timeout&lt;/a&gt; for mysql command-line client connections.&lt;br /&gt;&lt;br /&gt;In rare occasions, some developers may also be concerned with &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_net_read_timeout"&gt;net_read_timout&lt;/a&gt; - the amount of time mysqld will wait for data being transmitted to it in order to complete an operation. If you're sending data to mysqld and the sending process gets interrupted for a long time, this may also trigger the error listed above.&lt;br /&gt;&lt;br /&gt;On the network side, I've seen this type of error is when the network is having a problem between the application layer and the database. How do we know which is which? We do all we can to make sure that the application layer isn't causing these issues so that when this error pops up, it's far less likely to be a preventable software coding issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-1832407856578326542?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/1832407856578326542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2011/05/heavy-improper-connection-termination.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/1832407856578326542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/1832407856578326542'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2011/05/heavy-improper-connection-termination.html' title='Heavy improper connection termination creates disk full risk'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-2069112975511072092</id><published>2011-05-07T01:18:00.001-06:00</published><updated>2011-05-30T19:42:22.646-06:00</updated><title type='text'>Just for fun...</title><content type='html'>There are moments in every life when we ask ourselves - why do I do this?&lt;br /&gt;&lt;br /&gt;One of the reasons I enjoy doing what I do is to get away at times and go ride... In my case, a Honda Silver Wing (FSC600). I enjoy the "SWing" so much that I've made it a point to take it with me when I can. :-)&lt;br /&gt;&lt;br /&gt;Here are some of the places I've ridden so far... (updated 30May11)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-F0zOKBzAozo/TeRHIS4XBiI/AAAAAAAAAB0/ymIOHpUVtMI/s1600/VisitedStatesMap.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&amp;nbsp;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/-F0zOKBzAozo/TeRHIS4XBiI/AAAAAAAAAB0/ymIOHpUVtMI/s1600/VisitedStatesMap.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="161" src="http://1.bp.blogspot.com/-F0zOKBzAozo/TeRHIS4XBiI/AAAAAAAAAB0/ymIOHpUVtMI/s320/VisitedStatesMap.png" width="320" /&gt;&amp;nbsp;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-2069112975511072092?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/2069112975511072092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2011/05/just-for-fun.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/2069112975511072092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/2069112975511072092'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2011/05/just-for-fun.html' title='Just for fun...'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-F0zOKBzAozo/TeRHIS4XBiI/AAAAAAAAAB0/ymIOHpUVtMI/s72-c/VisitedStatesMap.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-3410712314783434435</id><published>2010-09-14T14:11:00.001-06:00</published><updated>2010-09-14T14:16:24.842-06:00</updated><title type='text'>Dude's Law: Meaningful Thinking</title><content type='html'>I had never really thought much about how coaches get to be really good at what they do. I (like many, I assume) think that being a really good player makes someone a good coach of players. Then I thought about the adage - "Practice doesn't make perfect, practice makes permanent. Right practice makes perfect." The problem is - without the right feedback, there is little chance of knowing that practice is right.&lt;br /&gt;&lt;br /&gt;The article I'm pointing to here inspired me to think more about "why" I do things. Why do I go to work each day besides earning a paycheck? Why do I blog? Why do I play disc golf? Why did I get married? Why do I stay married? Why did I make so many of the decisions I've made in my life?&lt;br /&gt;&lt;br /&gt;The more I ask why, the more I have to answer "so that." By being conscious of the "so that's," I think living life can become much easier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-3410712314783434435?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://devjam.com/dudesblog/dudes-law/trackback/' title='Dude&apos;s Law: Meaningful Thinking'/><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/3410712314783434435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2010/09/dudes-law-meaningful-thinking.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3410712314783434435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3410712314783434435'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2010/09/dudes-law-meaningful-thinking.html' title='Dude&apos;s Law: Meaningful Thinking'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-6756025195026155781</id><published>2010-05-14T14:10:00.002-06:00</published><updated>2010-05-14T14:12:21.126-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Timestamps in tables please</title><content type='html'>As MySQL DBA's, it helps us to understand when rows were added in a table and when those rows were last updated.  As a result, we're requesting that all tables have the following two columns in them to help us track those changes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;, created TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00'&lt;br /&gt;, updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This should help when it comes time to maintain rows in all your tables because the database knows how to handle these two columns by itself given the right scenario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&gt; CREATE TABLE foo (&lt;br /&gt;-&gt;     foo_id SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY&lt;br /&gt;-&gt;   , bar varchar(24) NOT NULL DEFAULT ''&lt;br /&gt;-&gt;   , created TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00'&lt;br /&gt;-&gt;   , updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP&lt;br /&gt;-&gt; ) ;&lt;br /&gt;Query OK, 0 rows affected (0.04 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; INSERT foo ( bar, created, updated )&lt;br /&gt;-&gt; VALUES ( 'hello', NULL, NULL )&lt;br /&gt;-&gt;      , ( 'world', NULL, NULL )&lt;br /&gt;-&gt;      ;&lt;br /&gt;Query OK, 2 rows affected (0.00 sec)&lt;br /&gt;Records: 2  Duplicates: 0  Warnings: 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice here that we intentionally insert NULL values into the created and updated columns.  These will be rows 1 and 2 below.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&gt; INSERT foo ( bar ) VALUES ( 'hello again' ) ;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This time, I'm not setting the created field at all so you can see what happens when we skip it.  I'm not crazy about this inconsistency, but it's what we have to work with for now.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mysql&gt; UPDATE foo SET bar = 'from here' WHERE foo_id = 2 ;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;Rows matched: 1  Changed: 1  Warnings: 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;mysql&gt; SELECT * FROM foo ;&lt;br /&gt;+--------+-------------+---------------------+---------------------+&lt;br /&gt;| foo_id | bar         | created             | updated             |&lt;br /&gt;+--------+-------------+---------------------+---------------------+&lt;br /&gt;|      1 | hello       | 2010-05-13 15:23:01 | 2010-05-13 15:23:01 |&lt;br /&gt;|      2 | from here   | 2010-05-13 15:23:01 | 2010-05-13 15:23:19 |&lt;br /&gt;|      3 | hello again | 0000-00-00 00:00:00 | 2010-05-13 15:23:03 |&lt;br /&gt;+--------+-------------+---------------------+---------------------+&lt;br /&gt;3 rows in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice that row 3's created column has the 0000-... default value in it.  Rows 1 and 2 don't because we actually inserted the NULL value into the NOT NULL column.  That demonstrates that inserting NULL into a TIMESTAMP column created with NOT NULL will cause the column to use the current time when an action is performed (INSERT/UPDATE/REPLACE).  This does not work with DATE, TIME, and DATETIME fields.&lt;br /&gt;&lt;br /&gt;Want to learn more?  Check out &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/timestamp.html"&gt;this link&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-6756025195026155781?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/6756025195026155781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2010/05/timestamps-in-tables-please.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6756025195026155781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6756025195026155781'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2010/05/timestamps-in-tables-please.html' title='Timestamps in tables please'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-767451494280083343</id><published>2010-03-28T14:13:00.001-06:00</published><updated>2010-03-28T14:13:41.631-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='None'/><title type='text'>Two of my favorite "toys"</title><content type='html'>&lt;img src="http://lh5.ggpht.com/_3qPHLqZUwXY/S6-4bHvR_HI/AAAAAAAAABU/M-8B8qKPea4/Two%20of%20my%20favorite%20%22toys%22_img_1.jpg" style="margin: 0pt 10px 10px 0pt; float: left cursor: pointer; width: 320px height: 240px; " height="240px" width="320px" /&gt;&lt;br&gt;&lt;br&gt;Doing work all day long can get rather boring.&amp;nbsp; So, here, I am showing off one of my hobbies.&amp;nbsp; The magazine is there for perspective in size.&amp;nbsp; The small helicopter is a Blade CP+ and the larger is a Bergen Gasser though not fully assembled.&amp;nbsp; As you can see, the Gasser is about 2.5 times the size of the Blade even with the training gear on.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-767451494280083343?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/767451494280083343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2010/03/two-of-my-favorite.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/767451494280083343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/767451494280083343'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2010/03/two-of-my-favorite.html' title='Two of my favorite &amp;quot;toys&amp;quot;'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_3qPHLqZUwXY/S6-4bHvR_HI/AAAAAAAAABU/M-8B8qKPea4/s72-c/Two%20of%20my%20favorite%20%22toys%22_img_1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-8317292578122350613</id><published>2010-02-08T18:31:00.027-07:00</published><updated>2010-05-17T15:25:07.676-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><category scheme='http://www.blogger.com/atom/ns#' term='How-To'/><title type='text'>Automatically Generate Configuration Files (Part 1)</title><content type='html'>&lt;style type="text/css"&gt;.codebox {  margin-left: 48pt;  padding: 6pt;  border: solid black 1pt;  background-color: rgb(240, 240, 240);}&lt;/style&gt;&lt;br /&gt;This article begins a series on using m4 to generate configurations for MySQL but applies to other configurations as well.  Why would I want to generate configurations versus just managing each configuration separately?  How often do we feel we need to make a change that applies to several instances all at once?  Wouldn't it be nice if there was an easy way to change something in one place so that wold be reflected in all the configuration files under our care?  What about when we want to see the same change in all the files except one or two?  What about when we want to see that change happen in only one or two files?&lt;br /&gt;&lt;br /&gt;There are a plethora of templating, macro, and text processing systems available that can help administrators deal with this type of challenge.  I am using m4 for my own needs because it is very simple to understand and maintain while retaining the flexibility I need to go far beyond standard search and replace.  I use m4 to help me generate configurations for mysql, httpd, bind(DNS), and other software.  Generating configurations makes it much easier for me to maintain, test, and version my changes across several systems.&lt;br /&gt;&lt;br /&gt;Enough of the lead-in, let's get started using m4 in a meaningful way.&lt;br /&gt;&lt;br /&gt;m4 is available on most Unix-based systems automatically.  If it's not available on yours, check your repositories.  On Windows, m4 is available in Cygwin.  If you don't already have Cygwin, it is a way to get many of the tools that run in Unix-based environments without having to run Unix free of charge.&lt;br /&gt;&lt;br /&gt;m4 is a macro processor that has its roots in the C language processors.  It takes a stream of text, looks for certain keywords and uses those as macros that are expanded based on the needs presented to it.  m4 can handle loops, conditionals, and other common programming constructs.  m4 is a tool that helps users by keeping repetition down to a minimum.&lt;br /&gt;&lt;br /&gt;m4 uses processing instructions to determine when it needs to do something.  I've told it only to read processing instructions that start with m4_ because I don't want it confusing my instructions with real information that needs to be left alone.  It's just a precaution, but a good one and I encourage you to use it as well.  To get m4 to require m4_, simply add a -P to your m4 command (as shown below).&lt;br /&gt;&lt;br /&gt;The first instruction I'll show you is m4_define - the root of all that's m4.  What good would a macro processor be if we couldn't define macros to be expanded?  Isn't that like having a sail boat without a sail?  Anyway, I digress.  The syntax for m4_define looks like this: m4_define(`defined_label', `macro expanded') with the defined_label being the text that m4 will substitue and macro expanded being what it will replace defined_label with.  Notice that I've wrapped these items with a back-tick and a regular tick.  This is important and I'll explain more about that in upcoming articles.  For now, let's get with the program! ;-)&lt;br /&gt;&lt;br /&gt;&lt;div class="codebox"&gt;&lt;pre&gt;$ cat my.cnf.m4&lt;br /&gt;m4_define(`DEF_SERVER_ID', 1)&lt;br /&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = DEF_SERVER_ID&lt;br /&gt;$ &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If we run this file through m4, we will get the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="codebox"&gt;&lt;pre&gt;$ m4 -P &amp;lt; my.cnf.m4&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = 1&lt;br /&gt;$ &lt;/pre&gt;&lt;/div&gt;Notice that the definition of the DEF_SERVER_ID variable seems to have disappeared.  That's true - m4 "ate" the definition macro.  The new line is still there but that's all that's left of the first line of the file.  What's cool, however, is we now have one place where the server ID was specified and another where it was used.  No big deal there - what value does that give me, you ask?  None at all unless you really like repeating yourself a lot.  Of course there is more.  Let's make this a little more meaningful.  &lt;br /&gt;&lt;div class="codebox"&gt;&lt;pre&gt;$ cat my.cnf.m4&lt;br /&gt;m4_define(`DEF_MYSQLDIR', `/var/lib/mysql')&lt;br /&gt;m4_define(`DEF_SERVER_ID', 1)&lt;br /&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = DEF_SERVER_ID&lt;br /&gt;log = DEF_MYSQLDIR/logs/mysql.log&lt;br /&gt;socket = DEF_MYSQLDIR/mysql.sock&lt;br /&gt;pid-file = DEF_MYSQLDIR/run/mysql.pid&lt;br /&gt;datadir = DEF_MYSQLDIR/data&lt;br /&gt;$ &lt;/pre&gt;&lt;/div&gt;Did you think through what m4 will do for us?  Think about your answer before you read further.  &lt;br /&gt;&lt;div class="codebox"&gt;&lt;pre&gt;$ m4 -P &amp;lt; my.cnf.m4&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = 1&lt;br /&gt;log = /var/lib/mysql/logs/mysql.log&lt;br /&gt;socket = /var/lib/mysql/mysql.sock&lt;br /&gt;pid-file = /var/lib/mysql/run/mysql.pid&lt;br /&gt;datadir = /var/lib/mysql/data&lt;br /&gt;$ &lt;/pre&gt;&lt;/div&gt;Pretty cool, eh?  Well - maybe not yet.  Did you get it right?  What if I decided I needed to move my MySQL instance to another directory like /opt/mysqlInstance1 ?  Rather than having to search for and replace all the text of "/var/lib/mysql" changing it to "/opt/mysqlInstance1", all I need to do is change the definition of DEF_MYSQLDIR at the top of the m4 template, then re-run m4 on my template and I get the new ouptut file.  That's what I call slick. :-)  &lt;br /&gt;&lt;div class="codebox"&gt;&lt;pre&gt;$ cat my.cnf.m4&lt;br /&gt;m4_define(`DEF_MYSQLDIR', `/opt/mysqlInstance1')&lt;br /&gt;m4_define(`DEF_SERVER_ID', 1)&lt;br /&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = DEF_SERVER_ID&lt;br /&gt;log = DEF_MYSQLDIR/logs/mysql.log&lt;br /&gt;socket = DEF_MYSQLDIR/mysql.sock&lt;br /&gt;pid-file = DEF_MYSQLDIR/run/mysql.pid&lt;br /&gt;datadir = DEF_MYSQLDIR/data&lt;br /&gt;$ m4 -P &amp;lt; my.cnf.m4&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = 1&lt;br /&gt;log = /opt/mysqlInstance1/mysql.log&lt;br /&gt;socket = /opt/mysqlInstance1/mysql.sockm4 &lt;br /&gt;pid-file = /opt/mysqlInstance1/run/mysql.pid&lt;br /&gt;datadir = /opt/mysqlInstance1/data&lt;br /&gt;$ &lt;/pre&gt;&lt;/div&gt;So - that's nice, but there's a lot more to m4 than just being able to define macros.  One of the most powerful tools that m4 offers is the ability to pull in other files.  I'll explain by example:  &lt;br /&gt;&lt;div class="codebox"&gt;&lt;pre&gt;$ cat my.cnf.m4&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = DEF_SERVER_ID&lt;br /&gt;log = DEF_MYSQLDIR/logs/mysql.log&lt;br /&gt;socket = DEF_MYSQLDIR/mysql.sock&lt;br /&gt;pid-file = DEF_MYSQLDIR/run/mysql.pid&lt;br /&gt;datadir = DEF_MYSQLDIR/data&lt;br /&gt;&lt;br /&gt;$ cat instance1.cnf.m4&lt;br /&gt;m4_define(`DEF_MYSQLDIR', `/opt/mysqlInstance1')m4_dnl&lt;br /&gt;m4_define(`DEF_SERVER_ID', 1)m4_dnl&lt;br /&gt;m4_include(`my.cnf.m4')&lt;br /&gt;$ cat instance2.cnf.m4&lt;br /&gt;m4_define(`DEF_MYSQLDIR', `/opt/mysqlInstance2')m4_dnl&lt;br /&gt;m4_define(`DEF_SERVER_ID', 2)m4_dnl&lt;br /&gt;m4_include(`my.cnf.m4')&lt;br /&gt;&lt;br /&gt;$ m4 -P &amp;lt; instance1.cnf.m4&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = 1&lt;br /&gt;log = /opt/mysqlInstance1/mysql.log&lt;br /&gt;socket = /opt/mysqlInstance1/mysql.sock&lt;br /&gt;pid-file = /opt/mysqlInstance1/run/mysql.pid&lt;br /&gt;datadir = /opt/mysqlInstance1/data&lt;br /&gt;&lt;br /&gt;$ m4 -P &amp;lt; instance2.cnf.m4&lt;br /&gt;[mysqld]&lt;br /&gt;server-id = 2&lt;br /&gt;log = /opt/mysqlInstance2/mysql.log&lt;br /&gt;socket = /opt/mysqlInstance2/mysql.sock&lt;br /&gt;pid-file = /opt/mysqlInstance2/run/mysql.pid&lt;br /&gt;datadir = /opt/mysqlInstance2/data&lt;br /&gt;&lt;br /&gt;$ &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;So - I added two things: m4_include and m4_dnl.  m4_include says basically go read this file and continue processing as if the text were part of this file.  m4_dnl says discard to next line.  It's a form of comment but I often use it to mean "don't new line."&lt;br /&gt;&lt;br /&gt;You notice in the example above, I created two very small files with the m4_define statements I needed (defining my macros) and then included the main template where those definitions were expanded as explained in the smaller files.  So - rather than creating one my.cnf file with the definitions for one instance then copying and hand-modifying that second file for the second instance, I am able to write one template and a couple of small definition files to get the same result.  If I need ot make a change to both files at the same time, I can simply change my my.cnf.m4 then re-generate my my.cnf files for each instance.&lt;br /&gt;&lt;br /&gt;In today's tutorial, you saw how to create and get m4 to expand basic macros, how to include other files into an m4 macro file, and how to create comments.  In our next episode, I'll explain how to make m4 smarter by showing you how to make it ask questions and do things differently depending on the answer.  I'll also explain how to get the make command to automatically handle creating all your configuration files for you as well as getting the files into source control.&lt;br /&gt;&lt;br /&gt;Do you like this series?  Please post a comment! :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-8317292578122350613?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/8317292578122350613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2010/02/automatic-generation-of-mysql-configs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/8317292578122350613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/8317292578122350613'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2010/02/automatic-generation-of-mysql-configs.html' title='Automatically Generate Configuration Files (Part 1)'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-6829307941439520242</id><published>2010-02-08T10:32:00.001-07:00</published><updated>2010-02-08T22:22:22.686-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>How to COUNT in SQL</title><content type='html'>Often, I see users attempting to count rows of a table with COUNT(*) as a part of their query.  Regardless of what database you're using, this probably not an optimal way to count.&lt;br /&gt;&lt;br /&gt;COUNT(*) is likely to cause the system to do a table scan to find out exactly how many rows are available.  Table scans are a very bad thing because it causes the system to go to disk to read the table.  COUNT(columnName) on a column that is indexed will allow the database to use the index to compute the count (meaning it reads less data and may even be able to do it entirely from RAM if the index is already loaded there).  The difference between COUNT(*) and COUNT(columnName) is a simple one - COUNT(*) counts every row where COUNT(columnName) counts the rows where columnName has a non-NULL value.&lt;br /&gt;&lt;br /&gt;My favorite way to do counts (when I don't already have a summary table telling me how many rows are in the result set I'm looking for) is to count the non-contextual primary key in the table since I make it a habit of putting a non-contextual primary key in every table I can.  This takes advantage of every possible optimization I can and keeps the amount of data the system must read down to a minimum.&lt;br /&gt;&lt;br /&gt;This is a great practice to be in because it helps not only in MySQL, but in other databases as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-6829307941439520242?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/6829307941439520242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2010/02/how-to-count-in-sql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6829307941439520242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6829307941439520242'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2010/02/how-to-count-in-sql.html' title='How to COUNT in SQL'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-61870859848653670</id><published>2010-01-07T20:41:00.002-07:00</published><updated>2010-02-08T22:23:09.934-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>MySQL Styles</title><content type='html'>There are nearly as many ways of writing SQL code as there are people writing it.  Each person has his or her own style.  While that may make it easy at one time or another for the writer, I suggest that using a well-recognized style makes it easier to read and maintain code (SQL or otherwise).  Good style also makes it easier to spot problems with code.  Whether you like the style I prefer or not, simply thinking about why others use one coding style over another can help us all communicate through our code better.&lt;br /&gt;&lt;br /&gt;Before I launch into the methods I'm using, I suggest you check out http://sqlinform.com/ (I'm not associated with the site, however, I use the free on-line SQL formatting tool there rather frequently).  When I'm trying to decipher someone else's code formatted in some other way (often just mashed together on a single or a few lines), this tool gives me a quick/easy way to re-format my code in a way that helps me read through the code.  It clearly delineates the pieces of the code structure and helps guide my eye through it.  Given the proper settings, I am able to read code so much easier that I am encouraging all the DBD's I work with to utilize this tool whether or not they're writing SQL for MySQL.&lt;br /&gt;&lt;br /&gt;Imagine you were handed a file that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;USE DBFOO; START TRANSACTION;&lt;br /&gt;DELIMITER ;;&lt;br /&gt;// SP_GET_FOO_DATA CREATED BY SOME BEGINNER TO MAKE IT EASIER TO MAINTAIN HOW FOO DATA IS RETRIEVED&lt;br /&gt;CREATE PROCEDURE SP_GET_FOO_DATA(V_FOO VARCHAR(2048)) SQL SECURITY INVOKER BEGIN SELECT SPLATTER.FOO, BLIP.BAR, BLOP.BAZ FROM BLIP LEFT JOIN SPLAT SPLATTER USING(SPLAT_ID), BLOP WHERE FOO = V_FOO AND BLIP.BLIP_ID = BLOP.BLIP_ID; END;; COMMIT;;&lt;br /&gt;DELIMITER ;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Don't run for the hills...  That's some funky code but let's see what we can do to clean it up:&lt;br /&gt;&lt;br /&gt;1) Using START TRANSACTION and COMMIT are both unnecessary here because DDL statements (like CREATE PROCEDURE, ALTER TABLE, CREATE TABLE, etc) implicitly call COMMIT for you whether or not you're in an active transaction.  MySQL silently ignores COMMITs when dealing with non-transactional storage engines but the point is, adding a COMMIT here doesn't add anything, so let's get rid of the excess transactional code.&lt;br /&gt;&lt;br /&gt;2) Adding a USE statement may or may not be appropriate.  At a minimum it makes deploying the code to a different database that much more difficult because the person applying it will need to change the USE statement accordingly.&lt;br /&gt;&lt;br /&gt;3) Am I the only one who finds it hard to read text in all caps all the time?  Okay - don't answer that.  Obviously, I'm not the only one who would rather see text mostly lower case and all caps only when it's time to draw the reader's attention to something special.&lt;br /&gt;&lt;br /&gt;4) The comment that is placed right before the CREATE PROCEDURE statement makes it hard to identify where the comment begins and ends versus where the code begins and ends.  These lines need to be a) split apart at a minimum.  It makes sense to me that the code would look and read better if the comment became a part of the DDL so it will show up in the SHOW PROCEDURE STATUS statement when called.&lt;br /&gt;&lt;br /&gt;5) Long lines are no fun to read when the line is longer than your screen width setting.  To get the whole picture, one must either decrease the font size to a sometimes unreadable value, or manually edit the file to break things up.  When I do reviews, I want to spend time reading code, not reformatting it.&lt;br /&gt;&lt;br /&gt;6) As I mentioned above, all caps makes it harder to follow text. It's a very common standard used by SQL writers that SQL clauses (like SELECT, WHERE, AND, VARCHAR, etc) are typically expressed in capital letters while database, table, column and variable names are expressed in lower case.  This makes it much easier to find the clause or parameters to a clause much easier when utilized in conjunction with the other methods below.&lt;br /&gt;&lt;br /&gt;7) Breaking up lines into logical groups helps the reader get the big picture fast.  When I am writing SQL code, I like to see my column listings in a group, each JOIN in a line group, the WHERE clause in a line group, etc.&lt;br /&gt;&lt;br /&gt;8) Combining implicit and explicit joins in MySQL 5 with a sql_mode of STRICT will cause MySQL to complain loudly.  Even if we hadn't used the explicit join in the middle, adding the implicit join after the explicit join throws many for a loop.  By writing explicit joins, we lead the reader through the code.&lt;br /&gt;&lt;br /&gt;9) When aliasing columns or tables, use the word AS even though it's not required.  This helps the reader quickly see that the table or column is being aliased.  Without it, the alias isn't as easy to find.&lt;br /&gt;&lt;br /&gt;10) Combining JOIN USING with implicit joins is typically a problem for MySQL and will likely cause a syntax error.  Consider being more explicit when using the USING clause.&lt;br /&gt;&lt;br /&gt;11) Positional sensitivity creates fragile code.  It's better to use order and group by with the names of the columns than their positional counterparts because the positional order can change without negatively impacting the functionality.&lt;br /&gt;&lt;br /&gt;I have some other rules I use for my own code that make it easier for me to read SQL.  Can you find them below?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;      USE dbFoo ;&lt;br /&gt;DELIMITER ;;&lt;br /&gt;   CREATE&lt;br /&gt;PROCEDURE sp_get_foo_data(&lt;br /&gt;                           v_foo VARCHAR(2048)&lt;br /&gt;                         )&lt;br /&gt;      SQL SECURITY INVOKER&lt;br /&gt;  COMMENT 'Make it easier to maintain how foo data is retrieved'&lt;br /&gt;    BEGIN&lt;br /&gt;          SELECT s.foo&lt;br /&gt;               , b1.bar&lt;br /&gt;               , b2.baz&lt;br /&gt;            FROM blip&lt;br /&gt;              AS b1&lt;br /&gt;&lt;br /&gt;            LEFT&lt;br /&gt;            JOIN splat&lt;br /&gt;              AS s&lt;br /&gt;              ON s.SPLAT_ID = b1.SPLAT_ID&lt;br /&gt;&lt;br /&gt;           INNER&lt;br /&gt;            JOIN blop&lt;br /&gt;              AS b2&lt;br /&gt;              ON b2.blip_id = b1.blip_id&lt;br /&gt;&lt;br /&gt;           WHERE s.foo = v_foo&lt;br /&gt;               ;&lt;br /&gt;      END ;;&lt;br /&gt;DELIMITER ;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can see I like to keep operators and SQL clauses to the left of a visual vertical column (right justified) and indent according to the level of code (new blocks like the begin/end block are indented).  I also prefer to be explicit with table aliases for each table in-use.  I go through this extra step when tables are being joined even if those names don't conflict.  This makes it easier to quickly indicate which table the column comes from.  When I have long lists of comma-separated lists of items (columns in this case), I like to treat the comma as an operator and start a new line right before the comma then indent according to the list.  I put the comma first because it makes adding and removing lines from the list much easier that way.  When it makes sense to do so, I also like to vertically align arithmetic, comparison, and assignment operators.&lt;br /&gt;&lt;br /&gt;I could go on, I think you might be able to see some of the why behind my own formatting preferences.  What preferences do you have and why?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-61870859848653670?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/61870859848653670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2010/01/mysql-styles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/61870859848653670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/61870859848653670'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2010/01/mysql-styles.html' title='MySQL Styles'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-3537358528160978521</id><published>2009-12-02T23:06:00.003-07:00</published><updated>2010-02-08T22:18:09.584-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><category scheme='http://www.blogger.com/atom/ns#' term='Cell Phones'/><title type='text'>Motorola Droid versus Blackberry 8830 World Edition</title><content type='html'>As a DBA, I often need to be available to perform work on databases I am responsible for when I am away from the office.  I have two phones - a corporate Blackberry 8830 World Edition and my personal Motorola Droid.  Both phones are fully featured and support a large number of applications.  Both phones are impressive in their own right on capabilities, though the thing I feel I miss most on the Blackberry is the turn-by-turn verbally announced directions (versus VZ Navigator on my old Glyde).  The ssh client in the Droid (ConnectBot) seems far more capable than the ssh client I use on my Blackberry.  I had difficulty learning the Blackberry development environment and while I didn't try terribly hard, I was not able to find a simulator to help me test my applications before deploying them to a Blackberry.  I did not have that problem at all with my Droid.  The Droid simulator was very easy to find and works wonderfully for me.  The integration into Eclipse also makes it very easy to utilize.&lt;br /&gt;&lt;br /&gt;With what I know about the Droid versus the Blackberry after a few months of use, for my needs, the Droid beats my 8830 hands down.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-3537358528160978521?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/3537358528160978521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/12/motorola-droid-versus-blackberry-8830.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3537358528160978521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3537358528160978521'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/12/motorola-droid-versus-blackberry-8830.html' title='Motorola Droid versus Blackberry 8830 World Edition'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-959007214747387406</id><published>2009-11-03T12:49:00.000-07:00</published><updated>2010-02-08T22:23:09.934-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Dave's Stuff: Cardinality</title><content type='html'>Here's some good stuff on cardinality I read recently.  It made me think to review my own understanding of the computation of cardinality in a table.  &lt;a href="http://dave-stokes.blogspot.com/2009/11/cardinality.html"&gt;Dave&amp;#39;s Stuff: Cardinality&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I didn't know that cardinality isn't a perfect computation of cardinality, rather a random sampling of values during an ANALYZE TABLE according to his description.&lt;br /&gt;&lt;br /&gt;Dave - The way I have been explaining cardinality to users is to discuss uniqueness of a value.  If a bin has n items in it, the highest cardinality possible is n if all the items in the bin are unique.  The lowest possible cardinality is 1.  The real value of cardinality is the relationship of the number of all items in the bin to the number of distinct items in the bin (key in this case).  One formula for determining this is...&lt;br /&gt;&lt;br /&gt;cardinality = total_items / distinct_items&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-959007214747387406?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://dave-stokes.blogspot.com/2009/11/cardinality.html' title='Dave&apos;s Stuff: Cardinality'/><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/959007214747387406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/11/daves-stuff-cardinality.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/959007214747387406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/959007214747387406'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/11/daves-stuff-cardinality.html' title='Dave&apos;s Stuff: Cardinality'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-8931489592202410212</id><published>2009-06-19T11:36:00.004-06:00</published><updated>2009-06-19T12:25:38.608-06:00</updated><title type='text'>Dynamic Memory Allocation in MySQL</title><content type='html'>Did you know that MySQL can dynamically allocate memory for queries?  I didn't till I found this web page...  &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/memory-use.html"&gt;http://dev.mysql.com/doc/refman/5.0/en/memory-use.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The connection buffer and result buffer both begin with a size given by net_buffer_length but are dynamically enlarged up to max_allowed_packet bytes as needed. The result buffer shrinks to net_buffer_length after each SQL statement. While a statement is running, a copy of the current statement string is also allocated.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;What's the big deal about this?  mysqld needs enough memory in order to transmit the entire result of a query.  If a query or result requires more than max_allowed_packet bytes, mysqld is unable to serve up the results.  While the table structure is built to support very large amounts of data, it's possible to design a table in such a way that mysqld won't be able to respond by asking it to send back too much data in a single row.&lt;br /&gt;&lt;br /&gt;I was surprised to learn that even if you can concat data into a text field, if the size of a retrieved data set exceeds max_allowed_packet bytes, the query will fail!  That sucks.  I was certain I had filed a bug on this years ago, but wasn't able to find it.  At any rate, http://bugs.mysql.com/bug.php?id=45625 has been filed recently. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-8931489592202410212?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://dev.mysql.com/doc/refman/5.0/en/memory-use.html' title='Dynamic Memory Allocation in MySQL'/><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/8931489592202410212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/06/dynamic-memory-allocation-in-mysql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/8931489592202410212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/8931489592202410212'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/06/dynamic-memory-allocation-in-mysql.html' title='Dynamic Memory Allocation in MySQL'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-4209563227779449609</id><published>2009-05-31T01:40:00.000-06:00</published><updated>2009-05-31T01:46:12.971-06:00</updated><title type='text'>What do you think? Test automation...</title><content type='html'>What do you think?  What are the advantages of how your approach works for you? Some say write tests after other code is done. Some prefer to write tests then code. Some want tests at the unit level. Some only care about testing API's. What are your thoughts?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-4209563227779449609?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/4209563227779449609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/05/what-do-you-think-test-automation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/4209563227779449609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/4209563227779449609'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/05/what-do-you-think-test-automation.html' title='What do you think? Test automation...'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-8770870623362419080</id><published>2009-04-25T12:19:00.004-06:00</published><updated>2009-04-28T10:40:15.085-06:00</updated><title type='text'>What should I use - stored procedures or application code?</title><content type='html'>&lt;iframe src="http://rcm.amazon.com/e/cm?t=k0c5-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0596100892&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="1" align="right"&gt;&lt;/iframe&gt;&lt;br /&gt;I've often thought about using a stored procedure versus using application code to accomplish tasks.  The rules I use are pretty simple:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Let the database generate data for itself (from data it already has).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Let the database maintain data security and integrity where appropriate.&lt;/li&gt;&lt;li&gt;Let the database help me administer it.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;I've chosen to shy away from asking the database to handle business logic internally for a number of reasons, largely because databases are typically very expensive resources in comparison to application servers.  It may also be difficult to revision business logic stored in the database, therefore making it more difficult to track how that code has changed.&lt;br /&gt;&lt;br /&gt;I do understand the value of stored procedures reducing network traffic for certain types of queries as well as guaranteeing the effective use of the query cache, however, I find that applications can be designed to use libraries of SQL in such a way that the query cache is used effectively and network traffic is reduced through the proper use of joins, cursors and temporary tables.&lt;br /&gt;&lt;br /&gt;Talking with other DBA's, some agree with me, some don't.  What are your thoughts about when to use stored procedures versus application code?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-8770870623362419080?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/8770870623362419080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/04/what-should-i-use-stored-procedures-or.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/8770870623362419080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/8770870623362419080'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/04/what-should-i-use-stored-procedures-or.html' title='What should I use - stored procedures or application code?'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-4079483049579214750</id><published>2009-04-25T10:48:00.007-06:00</published><updated>2010-02-08T22:25:34.353-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Creating a MySQL reference database in 3 easy steps</title><content type='html'>&lt;span style="font-weight: bold;"&gt;What is a reference database?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A reference database is nothing more than a set of data that developers and test systems use to mirror what production data looks like without actually exposing sensitive data from the production system.  This is critical for systems that handle HIPPA and PCI/DSS data because developers need to know what production looks and performs like, but they aren't allowed to see protected data like credit card numbers or medical data about specific individuals.&lt;br /&gt;&lt;br /&gt;There are a number of different goals a reference database typically covers:&lt;br /&gt;&lt;ul style="color: rgb(0, 153, 0);"&gt;&lt;li&gt;Provide a realistic snapshot of what developers need in order to be effective when maintaining most of the production code (i.e. the DDL and realistic data).&lt;/li&gt;&lt;li&gt;Provide a way to test edge cases without affecting production.&lt;/li&gt;&lt;li&gt;Provide a data set that realistically models production for performance testing of queries.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;How do I set up a basic reference database?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, the process of creating the reference database is pretty simple using replication.  I'll assume you're already using replication to provide back-up of your master data set (at minimum).  I'm also going to assume you are on MySQL 5 or newer.&lt;br /&gt;&lt;ol&gt;&lt;li style="color: rgb(0, 0, 153);"&gt;Create a replication slave that receives all data from your production master.&lt;/li&gt;&lt;li style="color: rgb(0, 0, 153);"&gt;Create triggers and corresponding stored procedures on this slave that obfuscate sensitive data.&lt;/li&gt;&lt;li&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;Utilize a cron or similar automated job to do a mysqldump of the resulting data set from time to time so that developers and testers can download it to their environments.&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;This accomplishes the goal of providing a production database snapshot in isolation without exposing sensitive data to others that aren't authorized to see it.  It also accomplishes the goal of providing a basis for testing performance of the database as well as a method for verifying edge cases.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How do I cover edge cases?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem is, this method probably won't cover edge cases by itself, but as I said above, it does provide the basis for it.  To cover edge cases that the production data doesn't cover, you'll need to write a script that will update a deployed copy of the reference database.  What happens if certain data is missing?  What if it's duplicated inappropriately?  How does the application react when a transaction table is full - does it automatically add another transaction table to the merge? ...  You know your application and the edge cases it needs.  Creating scripts to simulate these conditions should be relatively straightforward.&lt;br /&gt;&lt;br /&gt;Once you have a reference database and scripts to test performance and edge cases, it becomes terribly simple to add your database to your continuous integration system.  Deciding on how often to run those tests largely depends on how often you can afford to run the tests with the resources you have available to you.  Typically, I want to run a minimum set of tests for every code commit related to it, then run a full set of tests on a timed schedule so I don't overwhelm my build system.&lt;br /&gt;&lt;br /&gt;Has this helped you?  Do you have suggestions or comments that might help someone else?  Please feel free to add your comments here. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-4079483049579214750?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/4079483049579214750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/04/creating-mysql-reference-database-in-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/4079483049579214750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/4079483049579214750'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/04/creating-mysql-reference-database-in-3.html' title='Creating a MySQL reference database in 3 easy steps'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-5473483321717358954</id><published>2009-04-25T01:57:00.004-06:00</published><updated>2009-04-25T02:00:57.038-06:00</updated><title type='text'>Letting RSS help you with searches</title><content type='html'>Until recently, I never really thought much of using RSS to help me in this economy with job searches, but someone else did because sites like Dice, Monster, Indeed and Craigslist all provide ways to let your RSS reader keep you up-to-date with job search data.  I know - I'm giving away one of my search secrets, but if I don't tell you, someone else will.  Let's stick together and help each other out as we weather this recession.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-5473483321717358954?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/5473483321717358954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/04/letting-rss-help-you-with-searches.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/5473483321717358954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/5473483321717358954'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/04/letting-rss-help-you-with-searches.html' title='Letting RSS help you with searches'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-1302475125054795251</id><published>2009-01-20T22:45:00.005-07:00</published><updated>2010-02-08T22:23:31.193-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL Certification'/><category scheme='http://www.blogger.com/atom/ns#' term='How-To'/><title type='text'>When do I get a certification and why?</title><content type='html'>&lt;iframe src="http://rcm.amazon.com/e/cm?t=k0c5-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0672328127&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" align="right"&gt;&lt;/iframe&gt;I see questions like this on &lt;a href="http://www.linkedin.com/"&gt;LinkedIn - http://www.linkedin.com/&lt;/a&gt; very frequently.&lt;br /&gt;&lt;br /&gt;Will it help me make more money?  Will it help me get my foot in the door?  Are certifications just a waste of time?&lt;br /&gt;&lt;br /&gt;The answer to all these questions is: it depends.  I've been on both sides of job searching (looking for work and looking for workers) and I can tell you that I've seen lots of people who had or were looking for certifications.  My Certified MySQL 5 Database Administrator #5739 "ticket" has helped open doors for me.  I have seen people come to me looking for work with certifications obtained by cramming for exams to pass certifications without attempting to understand what they were memorizing.&lt;br /&gt;&lt;br /&gt;When I've interviewed (on both sides of the table), it's often been helpful to be able to explain how I used my certification in a real-world business scenario.  For example, I've been able to say things like this (honestly, of course) to an interviewer.  "I had been developing code against MySQL databases and administering those databases many years before I decided to obtain a MySQL certification of my own.  The additional learning I got from studying for the certification helped me be better at my job and exposed me to new concepts that helped me think in new ways about how to use MySQL."  Flipping that around, I've asked questions like - "Why did you get your certification?" and "What has the certification process done for you?"&lt;br /&gt;&lt;br /&gt;Are you just out of college and deciding on getting certified to gain an edge?  Go ahead, but better yet - if you can find an organization who can use those skills, even as a volunteer, it will likely have more credibility with an employer over someone who has a degree and certifications without experience.&lt;br /&gt;&lt;br /&gt;Looking for ways to use your MySQL certification?  Look for local clubs, non-profit's, and other similar groups that have a website, keep membership lists, or do other things where a database could help them.  If they already have someone that's maintaining their database, you might ask if you could shadow that person to help build skills.  If you end up getting some work out of it, great.  If not, at least you'll build contacts that could potentially help you find work or provide a professional reference for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-1302475125054795251?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/1302475125054795251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/when-do-i-get-certification-and-why.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/1302475125054795251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/1302475125054795251'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/when-do-i-get-certification-and-why.html' title='When do I get a certification and why?'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-2872415133322829450</id><published>2009-01-20T15:53:00.010-07:00</published><updated>2010-02-08T22:25:34.353-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Testing MySQL Query Results</title><content type='html'>&lt;iframe src="http://rcm.amazon.com/e/cm?t=k0c5-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0596101716&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" align="right"&gt;&lt;/iframe&gt;Often times, developers talk about testing code, but few spend the time to test data changes made in SQL adequately.  I've found that using code similar to this has been a real help to me in isolating potential bugs in how I've coded my own inserts, updates, and deletes.  Many would argue that there are better ways to do this, often from an external language, but when all you have is plain old SQL, there are effective ways to perform tests.&lt;br /&gt;&lt;br /&gt;Breaking it down, there are three basic steps I use:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Drop and re-create a table to store results in&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Write inserts to that table from selects that verify key parts of expected results&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Inspect the outcome of the tests&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Drop and re-create a table to store results in&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;SQL Code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DROP TABLE IF EXISTS test_resultset;&lt;br /&gt;CREATE TABLE test_resultset (&lt;br /&gt;    test_name    VARCHAR(255)         NOT NULL&lt;br /&gt;  , created      TIMESTAMP            NOT NULL DEFAULT CURRENT_TIMESTAMP&lt;br /&gt;  , passfail     ENUM('Pass', 'Fail') NOT NULL DEFAULT 'Fail'&lt;br /&gt;  , result_count INT UNSIGNED         NOT NULL DEFAULT 0&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Write inserts to that table from selects that verify key parts of expected results&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;INSERT INTO test_resultset ( test_name, passfail, result_count )&lt;br /&gt;SELECT '01 first_test_table.first_test_column' AS test_name&lt;br /&gt;     , IF( SOME CONDITION , 'Pass', 'Fail' )   AS passfail&lt;br /&gt;     , COUNT(*)                                AS result_count&lt;br /&gt;  ...&lt;br /&gt; GROUP&lt;br /&gt;    BY passfail&lt;br /&gt;     ;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Inspect the outcome of the tests&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT *&lt;br /&gt;  FROM test_resultset&lt;br /&gt;     ;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've found that when I write my tests first, it helps me know when I've written "enough" code to be able to say a particular step is complete.  When someone asks me what my code is supposed to do, I use my test cases to explain it to them.&lt;br /&gt;&lt;br /&gt;Recently, I made modifications to reports that were very intricate.  To make it easier on me, I wrote SQL code that verified my modifications before I made them.  I used tests that looked something like this (the real tables are named descriptively, unlike these):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;INSERT&lt;br /&gt;  INTO test_resultset&lt;br /&gt;SELECT '41 mlr.withheld_amount = SUM(mlrd.withheld_amount)' AS test_name&lt;br /&gt;     , IF( ABS( mlr.withheld_amount - mlrdj.withheld_amount ) &lt; 0.001&lt;br /&gt;         , 'Pass'&lt;br /&gt;         , 'Fail' ) AS passfail&lt;br /&gt;     , COUNT(*)&lt;br /&gt;  FROM mlr&lt;br /&gt;&lt;br /&gt;  JOIN&lt;br /&gt;     (&lt;br /&gt;       SELECT id&lt;br /&gt;            , SUM(withheld_amount) AS withheld_amount&lt;br /&gt;         FROM mlrd&lt;br /&gt;     )&lt;br /&gt;    AS mlrdj&lt;br /&gt;    ON mlr.mlrd_id = mlrdj.id&lt;br /&gt;&lt;br /&gt; GROUP&lt;br /&gt;    BY passfail&lt;br /&gt;     ;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When I looked at my result set, I saw my test passed, what the name of the test was, the number of records that matched, and the time when the test was last run.  I know to look for test 41 in my result set so that if the test doesn't show up, I know it didn't return any rows so it's likely that either my test is not valid or there is no data to run my test against.&lt;br /&gt;&lt;br /&gt;By storing the test results in a table, it also provides reference to help you know when you ran your last test set and gives you an easy way to find out what the results of each test were.&lt;br /&gt;&lt;br /&gt;If you wanted to keep results from multiple runs of tests, you may want to create a separate table that will give you a test run number, then add that to your test_resultset table as a cross-reference.  Then, removing data (like dropping the test_resultset table) between runs becomes not only unnecessary but undesirable.&lt;br /&gt;&lt;br /&gt;While this is a very rudimentary test method, it can save lots of work by giving yourself an easy way to run a test set quickly.  As you develop code, keeping a test set like this around (whether it's in a SQL file or driven by some other language), you'll find benefits from having test sets like this to rely on as your code becomes more robust and complex.&lt;br /&gt;&lt;br /&gt;I could go on, but I'm sure you get the idea and can see how useful this could be when verifying SQL code works as expected.  Want to learn more about writing tests before code?  Check out "Test Driven Development" in your favorite search engine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-2872415133322829450?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/2872415133322829450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/testing-mysql-query-results.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/2872415133322829450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/2872415133322829450'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/testing-mysql-query-results.html' title='Testing MySQL Query Results'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-3970388493675518599</id><published>2009-01-16T21:22:00.005-07:00</published><updated>2010-02-08T22:28:02.763-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Using top, mytop, mysql command-line all inside screen</title><content type='html'>This posting contains sample .screenrc and .mytop files.&lt;br /&gt;&lt;br /&gt;If you've never used screen before and you like using command-line things, check it out.  What I like most about screen is you can start a screen session, detach from it intentionally or otherwise, then reattach picking up right where you left off last time.  The easiest way to explain what screen does is simply stating that screen allows you to open (within reason) as many independent terminal sessions as your system will allow.  From each of these sessions, you can do pretty much anything you'd do from your regular terminal session.  Some of these sessions can be displayed back to you at the same time, some may be left running in the background.  In each session, however, screen tracks the session display just like a regular terminal would.&lt;br /&gt;&lt;br /&gt;I use screen personally to help me be aware of what's happening critically on my system, and to provide a constant point of reference I can get back to where I left off when I'm able.&lt;br /&gt;&lt;br /&gt;The top command is widely used by system administrators to see what processes are taking up the most resources on a given system.  Like top, mytop also helps DBA's to see what threads are utilizing resources quickly.  What many don't know is there are a number of things that can be done with mytop like killing active processes, turning off the header, setting up color, etc.&lt;br /&gt;&lt;br /&gt;When you combine these features with screen, it can be a very nice tool when doing administration and development of a database host.&lt;br /&gt;&lt;br /&gt;For example, over a telnet (very insecure) or ssh session, screen can present multiple session windows back to the user all, without needing a gui at all.&lt;br /&gt;&lt;br /&gt;My own .screenrc automatically sets up my windows for me like this:&lt;br /&gt;&lt;br /&gt;At the top, I automatically start top in a window that's 10 lines high.  This lets me see the most process-intensive commands running at any given time.&lt;br /&gt;&lt;br /&gt;The window below that is a mytop session to the database and shows me a list of the active queries at any given time (I filter out sleeping sessions and I don't generally display the headers giving me more space to see what queries are running.  I also have it updating once per second.&lt;br /&gt;&lt;br /&gt;In the third (bottom) window, I leave the rest of the lines to interact with MySQL, the shell, and other systems.&lt;br /&gt;&lt;br /&gt;You'll probably find these files interesting:&lt;br /&gt;&lt;br /&gt;$HOME/.mytop: (note: chmod 600 to protect your password from prying eyes)&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;&lt;code&gt;&lt;br /&gt;host=dbdev:3306&lt;br /&gt;user=me&lt;br /&gt;db=sys_trunk_db&lt;br /&gt;pass=my_pass&lt;br /&gt;delay=1&lt;br /&gt;port=3306&lt;br /&gt;socket=&lt;br /&gt;batchmode=0&lt;br /&gt;header=0&lt;br /&gt;color=1&lt;br /&gt;idle=0&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;$HOME/.screenrc&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# Make the escape key the backtick rather than ctrl-a since I use ctrl-a so much&lt;br /&gt;escape ``&lt;br /&gt;termcapinfo linux|xterm|rxvt|xterm-color ti@:te@:XT&lt;br /&gt;autodetach on&lt;br /&gt;autonuke on&lt;br /&gt;defflow off&lt;br /&gt;defscrollback 3000 # yes, that's lines&lt;br /&gt;startup_message off&lt;br /&gt;chdir&lt;br /&gt;vbell on&lt;br /&gt;vbell_msg "bell on %t (%n)"&lt;br /&gt;&lt;br /&gt;caption splitonly "%{= bw}%-Lw%{= wb}%50&gt; %n%f* %t %{-}%+Lw"&lt;br /&gt;&lt;br /&gt;hardstatus alwayslastline "%&lt; %= %{= bw} %H %{= rW} %l %{= bw} %m/%d %0c:%s %{-}"&lt;br /&gt;&lt;br /&gt;activity "Activity in %t(%n)"&lt;br /&gt;&lt;br /&gt;shelltitle "shell"&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;#  Toggle 'fullscreen' or not.&lt;br /&gt;#&lt;br /&gt;bind f eval "caption splitonly" "hardstatus ignore"&lt;br /&gt;bind F eval "caption always"    "hardstatus alwayslastline"&lt;br /&gt;&lt;br /&gt;# escape Control-R will reset my windows back to start-up sizes and locations.&lt;br /&gt;# It's nice for when I disconnect from screen then reconnect because screen&lt;br /&gt;# doesn't split windows by&lt;br /&gt;# default.&lt;br /&gt;bind ^R eval "only" "select 0" "split" "split" "focus top" "resize 10" "focus down" "select 1" "resize 12" "focus bottom" "select 2"&lt;br /&gt;&lt;br /&gt;# If a window goes unresponsive, don't block the whole session waiting for it.&lt;br /&gt;nonblock on&lt;br /&gt;&lt;br /&gt;bufferfile /home/me/screenPasteBuffer.txt&lt;br /&gt;&lt;br /&gt;msgwait 0&lt;br /&gt;screen -t top 0&lt;br /&gt;stuff "nice top \012"&lt;br /&gt;screen -t mytop@dbdev 1&lt;br /&gt;stuff "nice mytop \012"&lt;br /&gt;screen -t webdev001 2&lt;br /&gt;split&lt;br /&gt;split&lt;br /&gt;focus top&lt;br /&gt;select 0&lt;br /&gt;resize 10&lt;br /&gt;focus down&lt;br /&gt;select 1&lt;br /&gt;resize 12&lt;br /&gt;focus bottom&lt;br /&gt;screen -t dbdev001 3&lt;br /&gt;stuff "ssh dbdev001"&lt;br /&gt;screen -t dbreport001 4&lt;br /&gt;stuff "ssh dbdev001"&lt;br /&gt;screen -t webdev001 5&lt;br /&gt;stuff "ssh dbdev001"&lt;br /&gt;screen -t webdev001 6&lt;br /&gt;stuff "ssh dbdev001"&lt;br /&gt;select 2&lt;br /&gt;msgwait 2&lt;br /&gt;&lt;br /&gt;pow_detach_msg "Screen session of \$LOGNAME \$:cr:\$:nl:ended."&lt;br /&gt;shell -$SHELL&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;I can't take credit for all these enhancements.  On the other hand, I have tweaked them to suit my own needs.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-3970388493675518599?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/3970388493675518599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/using-top-mytop-mysql-command-line-all.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3970388493675518599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/3970388493675518599'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/using-top-mytop-mysql-command-line-all.html' title='Using top, mytop, mysql command-line all inside screen'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-2244812255041030107</id><published>2009-01-09T21:35:00.002-07:00</published><updated>2010-02-08T22:28:02.763-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Administration'/><title type='text'>Making the mysql command-line client work better</title><content type='html'>Baron Schwartz on &lt;a href="http://www.mysqlperformanceblog.com/2008/06/23/neat-tricks-for-the-mysql-command-line-pager/"&gt;www.mysqlperformanceblog.com&lt;/a&gt; posted a number of very nice tips on how to use the mysql command-line client.  Many of these pertain specifically to Unix-based clients, but some are rather useful in Windows as well. :-)&lt;br /&gt;&lt;br /&gt;If you're doing MySQL solo, I've often found mysqlperformanceblog.com to be rather useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-2244812255041030107?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/2244812255041030107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/easy-editing-with-mysql-command-line.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/2244812255041030107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/2244812255041030107'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/easy-editing-with-mysql-command-line.html' title='Making the mysql command-line client work better'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-4504649224520666590</id><published>2009-01-01T02:31:00.006-07:00</published><updated>2009-01-06T00:29:01.193-07:00</updated><title type='text'>MySQL Clustering vs. Replication (single &amp; multi-master)</title><content type='html'>There is a really cool method of implementing replication in MySQL (5.0.24+, 5.1.12+) that allows you to have more than one replication master server for a data set without clustering.  There are some really nice capabilities this gives you, however, there are some gotcha's with it too:&lt;br /&gt;&lt;br /&gt;Pro's:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Having dual replication  masters allows an administrator to take one of the masters off-line during an upgrade allowing the other master(s) to handle requests during that upgrade.  This provides a cheap form of high availability (HA).&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Hardware failures in a multi-master situation are less of an issue a s long as the software is configured to use more than one of the masters or a load balancer deals with sensing which host to use.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Given a large enough pipe, multi-mastering makes it possible to have a physically remote master.  You can't do that reliably with MySQL cluster (not replicated) because it requires extremely fast connections between the nodes of the cluster.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;No storage engine changes are required to implement for MyISAM (as opposed to Cluster requiring changing to NDB - a transactional storage engine).&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Con's:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Locking/Updating Race: It's possible for a lock to succeed in multiple masters simultaneously then fail on the "other" master(s).  For example, a user double-clicks a submit causing the application to start two different threads of the same type.  It's possible that neither will know about the other until it's "too late" if each thread gets a different DB server connection.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Each DB still needs to have a full copy of the entire data set unlike cluster which can distribute copies of data across multiple servers.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Suffers from al the problems of replication and the fragility it introduces.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;requires modifications to every table using auto_increment primary keys.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Tables that don't use an auto-increment field as the primary key or tables that have a UNIQUE key constraint on a column or set of columns may allow inserts to succeed on separate masters then fail in replication.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;MySQL multi-master replication can be a cheap alternative to MySQL cluster without some of the issues introduced by changing storage engines and incurring the expense of setting up the number of servers (and associated RAM, disk, networking, etc.) required to make MySQL cluster work efficiently.&lt;br /&gt;&lt;br /&gt;To learn more about MySQL Multi-Master Replication, see:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.howtoforge.com/mysql_master_master_replication"&gt;http://www.howtoforge.com/mysql_master_master_replication&lt;/a&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.1/en/replication-howto.html"&gt;http://dev.mysql.com/doc/refman/5.1/en/replication-howto.html&lt;/a&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.mysql.com/training/courses/mysql_5_ha.html"&gt;http://www.mysql.com/training/courses/mysql_5_ha.html&lt;/a&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.google.com/search?hl=en&amp;q=mysql+master+master+replication+auto_increment+site%3Adev.mysql.com"&gt;http://www.google.com/search?hl=en&amp;q=mysql+master+master+replication+auto_increment+site%3Adev.mysql.com&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-4504649224520666590?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/4504649224520666590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/mysql-clustering-vs-replication-single.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/4504649224520666590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/4504649224520666590'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2009/01/mysql-clustering-vs-replication-single.html' title='MySQL Clustering vs. Replication (single &amp; multi-master)'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-6485377283005765983</id><published>2008-12-30T22:59:00.000-07:00</published><updated>2010-02-08T22:25:34.354-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Best Practice'/><title type='text'>Using an effective_date column in MySQL</title><content type='html'>There are times when I blog about things just because it's a nice place to share knowledge about how to get things done that aren't always obvious or straightforward.  This is one of those things.&lt;br /&gt;&lt;br /&gt;I have a table of "stuff" that uses an "effective date" to determine when a particular entry should be available.  In this case, I want the largest effective date that's also not greater than the current moment.  Sure - I could use a start and end date, but that would be a waste because it implies I know when I will stop using returned rows.&lt;br /&gt;&lt;br /&gt;Let's assume I am showing users time-sensitive information from the following table (please ignore the lack of additional indexing):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;CREATE TABLE user_notification (&lt;br /&gt;   id             MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY&lt;br /&gt; , category_id    MEDIUMINT UNSIGNED NOT NULL&lt;br /&gt; , effective_date DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00'&lt;br /&gt; , is_active      TINYINT(1) NOT NULL DEFAULT 1&lt;br /&gt; , message        MEDIUMTEXT NOT NULL&lt;br /&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, let's assume that I only want to display the most up-to-date messages that are active for a given set of categories.  There is one option that works for me no matter how many categories I use.  It requires me to select and join from my user_notification table twice.  When combining this data with other parts of a select, it will wind up being two joins.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  SELECT NOW() INTO @compare_date;&lt;br /&gt;  SELECT un.*&lt;br /&gt;    FROM user_notification&lt;br /&gt;      AS un&lt;br /&gt;&lt;br /&gt;    LEFT&lt;br /&gt;    JOIN user_notification&lt;br /&gt;      AS un2&lt;br /&gt;      ON un2.id = un.id&lt;br /&gt;     AND un2.effective_date &gt; un.effective_date&lt;br /&gt;&lt;br /&gt;   WHERE un.effective_date &lt;= @compare_date&lt;br /&gt;     AND un2.effective_date IS NULL&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This might look a little strange, but here's how it works.  Notice that the left join simply re-joins the same table back against the select, but, it's attempting to find the largest possible effective_date.  The select's where clause limits us down to rows that are smaller than the compare date (NOW()).&lt;br /&gt;&lt;br /&gt;This is one of those queries that may not come easily at first, but once you've done it a few times, you'll be able to crank out similar queries with ease.&lt;br /&gt;&lt;br /&gt;Giving credit where credit is due - Thanks to my co-worker Brian P. for turning me on to this particular method of solving a similar problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-6485377283005765983?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/6485377283005765983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2008/12/using-effectivedate-column-in-mysql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6485377283005765983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/6485377283005765983'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2008/12/using-effectivedate-column-in-mysql.html' title='Using an effective_date column in MySQL'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-5897340224724276535</id><published>2008-12-30T16:20:00.000-07:00</published><updated>2010-02-08T22:18:09.584-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Reviews'/><category scheme='http://www.blogger.com/atom/ns#' term='Cell Phones'/><title type='text'>Review: Samsung Glyde phone</title><content type='html'>Rating: 2 (0=toss in trash, 10=give as nice gifts) in a DBA/IT operational environment.&lt;br /&gt;&lt;br /&gt;This phone sucks.  It has the worst user interface I've seen in any phone since I started using them more than ten years ago.  What's wrong with this phone?  Plenty.&lt;br /&gt;&lt;br /&gt;The screen is heat sensitive (not touch sensitive) so accidentally allowing your face to touch the phone at one of the button points will activate the pad and likely send the person on the other end (and your ear, of course) a really annoying tone.  Also, because it's heat sensitive, if you're into doing things outdoors when it's cold (I bike year-round), the phone may not be able to sense your keypresses in the event your fingers get cold enough.  I suppose I could learn to live with these "features" if it weren't for my next major gripe.&lt;br /&gt;&lt;br /&gt;Often, when I touch the pad, the phone thinks I'm pressing somewhere on the phone that's nowhere near where I'm pressing.  For example, when in portrait mode, I unlock the pad (so I don't annoy the person on the other hand when the phone bumps my face), then want to click the end button.  If I've typed any keys accidentially or intentionally, it isn't there, so I have to click on the "back" button.  Assuming I can press that button (I often can't for the same reason that will become very apparent in a moment), often when the phone is cold, I press the end button on the pad and I can watch it display a depressed button two buttons to the left of the end button.  When that happens, I am forced to either wait for the person on the other end to hang up, or power the phone off using a button on the side.&lt;br /&gt;&lt;br /&gt;If you thought this phone had a standard USB-sized port on the side for charging, forget it.  I thought I would be able to use this phone more like a PDA and transfer appointments to/from it, synchronize my settings with my laptop, and other handy similar things you can do with almost any PDA.  I guess Samsung didn't think that was very important so (at least on my Verizon version), the only way I can sync things is through their web-based service and even that is only limited to contacts. :-(&lt;br /&gt;&lt;br /&gt;The web browser sort-of supports Javascript, so using sites like Blogger.com are difficult at best (when you're turned off Javascript support in the phone).  Of course, when you do that, you loose the ability to use the nice WYSIWYG editor we're so used to.  Even if you turn off Javascript, you're limited to 2,048 keystrokes and you can't send the ENTER key like you can on a regular computer.  How lame.&lt;br /&gt;&lt;br /&gt;Signal with the Glyde on the Verizon network in and around Denver has been "okay" but definitely not great.  My Qwest phone had fewer dropped calls and low signal issues than this phone.  I am  not sure if it's the phone, the network, or the locations I'm operating the phone from, but I'm not impressed at this point.&lt;br /&gt;&lt;br /&gt;The Glyde also has some pretty tight restrictions on memory available.  Just to copy a single CD-worth of 56Kbps .wmv files onto the phone, I had to add a MicroSD card to the phone.  Want to listen to music privately?  You'll need an adapter to bring your headphone size down if you're used to using the same headphones you use on your laptop or desktop computer.&lt;br /&gt;&lt;br /&gt;The camera operation is "okay" as well, however, it often gets confused and enters recording mode when I just want a snapshot.&lt;br /&gt;&lt;br /&gt;Having talked to a number of Verizon reps, I've learned that this phone is Verizons most problematic offering today.&lt;br /&gt;&lt;br /&gt;Okay - having said all that "bad stuff" I think it's only fair to talk about some of the good (though difficult to find) things.  I do like that it comes with both a wall-based charger and a USB cable to transfer music to the phone that can also act as a charger for the phone as well.  I like the operation of the sliding mechanism and how it protects the keyboard.  I also like that when viewing web pages, I can zoom in or out.&lt;br /&gt;&lt;br /&gt;All in all, if I had known then (when I bought the phone) what I know now, I would never have even looked at the Glyde.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-5897340224724276535?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/5897340224724276535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2008/12/review-samsung-glyde-phone.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/5897340224724276535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/5897340224724276535'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2008/12/review-samsung-glyde-phone.html' title='Review: Samsung Glyde phone'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9152889102684049863.post-7097709455572818116</id><published>2008-12-29T15:01:00.000-07:00</published><updated>2010-02-08T22:23:31.194-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL Certification'/><category scheme='http://www.blogger.com/atom/ns#' term='How-To'/><title type='text'>MySQL CMDBA Certification Tips</title><content type='html'>Taking (and passing, of course) both the MySQL 5 CMDBA (Certified MySQL Database Administrator) examinations are all that's required to become a MySQL 5 CMDBA.&lt;br /&gt;&lt;br /&gt;What did I do to prepare to take the exams?  It helped that I've been using MySQL for a number of years, however, that isn't a prerequisite.  MySQL offers a certification class that does a fair job of preparing attendees for the exam.  However, even my class instructor suggested attendees go back to the book to continue practicing the exercises given and reading materials from the book.  The book he was referring to is the very same book you can get at your local book store - MySQL 5 Certification Study Guide.&lt;br /&gt;&lt;br /&gt;Knowing what I know now, with my experience, I could probably have passed the exams without the class, though taking the class exposed me to information I wouldn't have easily learned otherwise.  That additional knowledge helped me become a better CMDBA.&lt;br /&gt;&lt;br /&gt;If I had it to do over again, I would likely have used this approach:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Get the MySQL 5 Certification Study Guide&lt;/li&gt;&lt;li&gt;Read each DBA chapter carefully&lt;/li&gt;&lt;li&gt;Work through each of the exercises given in the study guide.&lt;/li&gt;&lt;li&gt;Find someone who is already certified to help me verify my answers.&lt;/li&gt;&lt;li&gt;Print a copy of the Q&amp;amp;A section on the included CD's&lt;/li&gt;&lt;li&gt;Answer each question without looking at the included answers first.&lt;/li&gt;&lt;li&gt;Study materials related to any questions I missed, then go back and take the sample questions again until I was able to pass easily.&lt;/li&gt;&lt;li&gt;When a particular topic proved especially difficult, I would have made up my own multiple choice questions right from the details given in the study guide.&lt;/li&gt;&lt;/ul&gt;Remember that the exams are based on a specific verison of MySQL 5 that is documented in the study guide.  Some of the capabilities of MySQL have changed since the book and corresponding exams were written.  The answer the exam is looking for is based on expectations at that time, not based on current performance and capabilities.&lt;br /&gt;&lt;br /&gt;Good news - when I took my MySQL 5 CMDBA examinations, I was allowed to review answers I had already given (or not given) before submitting the answers back through the system.  If in doubt about a question, don't let it bog you down.  Make a note on the question and come back to it with the whiteboard or paper the proctor will provide.  That way, you can get as many questions answered as possible.  If early questions take big chunks of time to answer, that can hurt you if you don't finish some of the questions later in the exam.&lt;br /&gt;&lt;br /&gt;One other note, if you have difficulty with a particular question (i.e. it seems ambiguous), make sure you comment on the question explaining why you answered the way you did.  If the question really is ambiguous, then when your exam results go for review, the reviewers will see your comments explaining your thinking.  This can help improve the test.&lt;br /&gt;&lt;br /&gt;Why did I take the exams?  Besides gaining the certification, I wanted to improve my knowledge of MySQL 5 specifically.  I also wanted something I could put on my resume that helped show that not only had I done work on MySQL 5 systems, but I became certified on them in the process.  That has helped me with credibility in interviews.&lt;br /&gt;&lt;br /&gt;Oh - one other thing I almost forgot - on the day of each exam - I actually chose to take off early from work, then spend an hour in the coffee shop near the exam site just to make sure I knew the answers to the questions I had previously missed.  It proved helpful.  I also took the night prior to the exams off just to make sure my mind could relax.  I also made it easier on myself by scheduling my exams for the afternoon, and I stayed away from certain foods I knew would make me tired that day (like turkey sandwiches at lunch) and other foods that would make me nervous or jumpy (caffine drinks for example).&lt;br /&gt;&lt;br /&gt;Good luck on your exams :-)&lt;br /&gt;&lt;br /&gt;KB&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9152889102684049863-7097709455572818116?l=kbcmdba.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kbcmdba.blogspot.com/feeds/7097709455572818116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://kbcmdba.blogspot.com/2008/12/mysql-cmdba-certification-tips.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/7097709455572818116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9152889102684049863/posts/default/7097709455572818116'/><link rel='alternate' type='text/html' href='http://kbcmdba.blogspot.com/2008/12/mysql-cmdba-certification-tips.html' title='MySQL CMDBA Certification Tips'/><author><name>kbcmdba</name><uri>http://www.blogger.com/profile/00580022235350884000</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
