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

<channel>
	<title>Boy Plankton . com &#187; Database</title>
	<atom:link href="http://www.boyplankton.com/category/computers/administration/database/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.boyplankton.com</link>
	<description></description>
	<lastBuildDate>Tue, 12 May 2009 03:32:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title></title>
		<link>http://www.boyplankton.com/2009/05/11/143/</link>
		<comments>http://www.boyplankton.com/2009/05/11/143/#comments</comments>
		<pubDate>Tue, 12 May 2009 03:32:45 +0000</pubDate>
		<dc:creator>Boy Plankton</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://www.boyplankton.com/?p=143</guid>
		<description><![CDATA[I&#8217;ve been trying to write a bunch of scripts that perform some database administration tasks in Groovy.  Groovy offers a several advantages over most of my other options.  It runs practically everywhere.  There are JDBC drivers available for every database that I have to work with.  Most importantly to me though, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been trying to write a bunch of scripts that perform some database administration tasks in <a href="http://groovy.codehaus.org/">Groovy</a>.  Groovy offers a several advantages over most of my other options.  It runs practically everywhere.  There are JDBC drivers available for every database that I have to work with.  Most importantly to me though, SQL programming in Groovy is really simple.</p>
<p>At first I thought it was a Groovy limitation that was causing my scripts to run out of heap space when I ran them against large tables.  It turned out to be the <a href="http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-implementation-notes.html">default behavior of the MySQL JDBC driver</a> though.</p>
<blockquote><p>By default, <strong>ResultSets are completely retrieved and stored in memory</strong>. In most cases this is the most efficient way to operate, and due to the design of the MySQL network protocol is easier to implement. If you are working with ResultSets that have a large number of rows or large values, and can not allocate heap space in your JVM for the memory required, you can tell the driver to stream the results back one row at a time.</p></blockquote>
<p>The solution is to override three default settings.  The first two override the default settings of the ResultSets that will be returned by the statement.<br />
<code>sql.setResultSetType( java.sql.ResultSet.TYPE_FORWARD_ONLY )<br />
sql.setResultSetConcurrency( java.sql.ResultSet.CONCUR_READ_ONLY )</code></p>
<p>This one adds a closure that gets called every time a statement gets created.<br />
<code>sql.withStatement{ stmt -> stmt.setFetchSize( Integer.MIN_VALUE ) }</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.boyplankton.com/2009/05/11/143/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Compound Indexes</title>
		<link>http://www.boyplankton.com/2007/03/27/compound-indexes/</link>
		<comments>http://www.boyplankton.com/2007/03/27/compound-indexes/#comments</comments>
		<pubDate>Wed, 28 Mar 2007 04:33:26 +0000</pubDate>
		<dc:creator>Boy Plankton</dc:creator>
				<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://www.boyplankton.com/2007/03/27/compound-indexes/</guid>
		<description><![CDATA[Important rule, MySQL only supports using one index per join.
If a multiple-column index exists on col1 and col2, the appropriate rows can be fetched directly. If separate single-column indexes exist on col1 and col2, the optimizer tries to find the most restrictive index by deciding which index finds fewer rows and using that index to [...]]]></description>
			<content:encoded><![CDATA[<p>Important rule, MySQL only supports using <a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html">one index per join</a>.</p>
<blockquote><p>If a multiple-column index exists on col1 and col2, the appropriate rows can be fetched directly. If separate single-column indexes exist on col1 and col2, the optimizer tries to find the most restrictive index by deciding which index finds fewer rows and using that index to fetch the rows.</p></blockquote>
<p>To demonstrate this I went and got some historical stock price data from <a href="http://biz.swcp.com/stocks/">this site</a>.  After that, I created a test table and added some indexes in order to test some concepts.<br />
<span id="more-104"></span></p>
<pre>
<font color="#ffff60">CREATE</font> <font color="#ffff60">TABLE</font> stockdata (
   sdate <font color="#60ff60">DATE</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> ,
   ticker <font color="#60ff60">VARCHAR( </font><font color="#ffa0a0">4</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> ,
   open <font color="#60ff60">DECIMAL( </font><font color="#ffa0a0">8</font><font color="#60ff60">,</font><font color="#ffa0a0">2</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> ,
   high <font color="#60ff60">DECIMAL( </font><font color="#ffa0a0">8</font><font color="#60ff60">,</font><font color="#ffa0a0">2</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> ,
   low <font color="#60ff60">DECIMAL( </font><font color="#ffa0a0">8</font><font color="#60ff60">,</font><font color="#ffa0a0">2</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> ,
   close <font color="#60ff60">DECIMAL( </font><font color="#ffa0a0">8</font><font color="#60ff60">,</font><font color="#ffa0a0">2</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> ,
   volume <font color="#60ff60">INT</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font>
) ENGINE = <font color="#ffff60">MYISAM</font> ;

<font color="#ffff60">load</font> <font color="#ffff60">data</font> <font color="#ffff60">infile</font> <font color="#ffa0a0">'sp500hst.txt'</font>
<font color="#ffff60">into</font> <font color="#ffff60">table</font> stockdata
<font color="#ffff60">fields</font> <font color="#ffff60">terminated</font> <font color="#ffff60">by</font> <font color="#ffa0a0">','</font>;

<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_sdate <font color="#ffff60">on</font> stockdata ( sdate );
<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_ticker <font color="#ffff60">on</font> stockdata ( ticker );</pre>
<p>With the data loaded and indexes created on the ticker field and the sdate field, we&#8217;re ready to take a look at why this is important.  Here&#8217;s the query that we&#8217;re going to use to test with:</p>
<pre>
<font color="#ffff60">explain</font> extended
<font color="#ffff60">select</font> *
<font color="#ffff60">from</font> stockdata
<font color="#ffff60">where</font> ticker = <font color="#ffa0a0">'DIS'</font>
<font color="#ffff60">and</font> sdate <font color="#ffff60">between</font>
   <font color="#ffa0a0">'2007-02-01'</font> <font color="#ffff60">and</font> <font color="#ffa0a0">'2007-02-28'</font>;</pre>
<pre>
+----+-------------+-----------+------+--------------------+-----------+---------+-------+------+-------------+
| id | select_type | table     | type | possible_keys      | key       | key_len | ref   | rows | Extra       |
+----+-------------+-----------+------+--------------------+-----------+---------+-------+------+-------------+
|  1 | SIMPLE      | stockdata | ref  | ix_sdate,ix_ticker | ix_ticker | 6       | const |  245 | Using where |
+----+-------------+-----------+------+--------------------+-----------+---------+-------+------+-------------+</pre>
<p>According to the results of our EXPLAIN, the optimizer chose to use the index on the ticker field, but not the index on the sdate field.  It chose that index because there are only 253 entries in the data with a ticker of &#8216;DIS&#8217;, but there are 9501 entries with an sdate in Feb 2007.  Basically, the plan is for it to grab all 253 &#8216;DIS&#8217; entries, and then it will apply a filter to them in order to find the ones that are within the date range that we are looking for.  Note that under &#8216;rows&#8217;, the optimizer thinks that this index will return 245 rows instead of 253.</p>
<p>This isn&#8217;t exactly ideal.  It would be nice to have the database utilize indexes on both those fields.  Since the database can only use one index per join, we will have to rely on a multiple-column ( aka compound ) index to get the desired performance.</p>
<pre>
<font color="#ffff60">drop</font> <font color="#ffff60">index</font> ix_sdate <font color="#ffff60">on</font> stockdata;
<font color="#ffff60">drop</font> <font color="#ffff60">index</font> ix_ticker <font color="#ffff60">on</font> stockdata;

<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_compound <font color="#ffff60">on</font> stockdata( sdate, ticker );</pre>
<pre>+----+-------------+-----------+-------+---------------+-------------+---------+------+------+-------------+
| id | select_type | table     | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------+---------------+-------------+---------+------+------+-------------+
|  1 | SIMPLE      | stockdata | range | ix_compound   | ix_compound | 9       | NULL | 8872 | Using where |
+----+-------------+-----------+-------+---------------+-------------+---------+------+------+-------------+</pre>
<p>According to the optimizer it&#8217;s going to have to filter through 8872 rows.  This appears to be less efficient than just having the index on the ticker field.  Why?  Because the order of the columns in a multiple-column index is very important and should be from most selective to least. In this example, we&#8217;ve ordered them just the opposite.  Instead, let&#8217;s drop that index and recreate it with the fields in the opposite order:</p>
<pre>
<font color="#ffff60">drop</font> <font color="#ffff60">index</font> ix_compound <font color="#ffff60">on</font> stockdata;
<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_compound <font color="#ffff60">on</font> stockdata( ticker, sdate );</pre>
<pre>
+----+-------------+-----------+-------+---------------+-------------+---------+------+------+-------------+
| id | select_type | table     | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------+---------------+-------------+---------+------+------+-------------+
|  1 | SIMPLE      | stockdata | range | ix_compound   | ix_compound | 9       | NULL |   14 | Using where |
+----+-------------+-----------+-------+---------------+-------------+---------+------+------+-------------+</pre>
<p>Down to an estimated 14 rows.  The query actually returns 19.  By utilizing a multiple-column index and carefully selecting the order of the columns in the index, I think this is about the best performance that we can get out of this query by just adjusting the indexes.  I&#8217;m certain that there are other optimizations that could be performed.  For instance, I could have done a better job structuring the table.  Different data types would probably occupy less space on disk, require fewer IO reads, etc &#8230; That said, playing with these indexes probably gets us the biggest bang for the buck.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boyplankton.com/2007/03/27/compound-indexes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL Indexes</title>
		<link>http://www.boyplankton.com/2007/03/25/mysql-indexes/</link>
		<comments>http://www.boyplankton.com/2007/03/25/mysql-indexes/#comments</comments>
		<pubDate>Mon, 26 Mar 2007 05:01:05 +0000</pubDate>
		<dc:creator>Boy Plankton</dc:creator>
				<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://www.boyplankton.com/2007/03/25/mysql-indexes/</guid>
		<description><![CDATA[It dawned on me this morning, following a conversation with Casey, that I don&#8217;t know nearly enough about MySQL database administration.  The vast majority of my DB experience is with Informix and Oracle.  So, I did a little reading up and performed some experiments.

First question that I had was how to analyze the [...]]]></description>
			<content:encoded><![CDATA[<p>It dawned on me this morning, following a conversation with <a href="http://gl-casey.livejournal.com/">Casey</a>, that I don&#8217;t know nearly enough about MySQL database administration.  The vast majority of my DB experience is with Informix and Oracle.  So, I did a little reading up and performed some experiments.<br />
<span id="more-103"></span><br />
First question that I had was how to analyze the queries, and the tables, to determine when/which indexes should be applied.  To begin I created a test database called monkey with just a few tables:</p>
<pre>
<font color="#ffff60">CREATE</font> <font color="#ffff60">TABLE</font> `<font color="#ffff60">order</font>` (
`id` <font color="#60ff60">INT</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> <font color="#ffff60">AUTO_INCREMENT</font> <font color="#ffff60">PRIMARY</font> <font color="#ffff60">KEY</font> ,
`name` <font color="#60ff60">VARCHAR( </font><font color="#ffa0a0">20</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font>
) ENGINE = INNODB ;

<font color="#ffff60">CREATE</font> <font color="#ffff60">TABLE</font> `suborder` (
`id` <font color="#60ff60">INT</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> <font color="#ffff60">AUTO_INCREMENT</font> <font color="#ffff60">PRIMARY</font> <font color="#ffff60">KEY</font> ,
`order_id` <font color="#60ff60">INT</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font>,
`name` <font color="#60ff60">VARCHAR( </font><font color="#ffa0a0">20</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font>
) ENGINE = INNODB ;

<font color="#ffff60">CREATE</font> <font color="#ffff60">TABLE</font> `infraorder` (
`id` <font color="#60ff60">INT</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font> <font color="#ffff60">AUTO_INCREMENT</font> <font color="#ffff60">PRIMARY</font> <font color="#ffff60">KEY</font> ,
`suborder_id` <font color="#60ff60">INT</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font>,
`name` <font color="#60ff60">VARCHAR( </font><font color="#ffa0a0">20</font><font color="#60ff60"> )</font> <font color="#ffff60">NOT</font> <font color="#ffa500">NULL</font>
) ENGINE = INNODB ;

<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `<font color="#ffff60">order</font>` ( name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">'Primates'</font> );

<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `suborder` ( order_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">1</font>, <font color="#ffa0a0">'Strepsirrhini'</font> );
<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `suborder` ( order_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">1</font>, <font color="#ffa0a0">'Haplorrhini'</font> );

<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `infraorder` ( suborder_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">1</font>, <font color="#ffa0a0">'Lemuriformes'</font> );
<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `infraorder` ( suborder_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">1</font>, <font color="#ffa0a0">'Chiromyiformes'</font> );
<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `infraorder` ( suborder_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">1</font>, <font color="#ffa0a0">'Lorisiformes'</font> );
<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `infraorder` ( suborder_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">2</font>, <font color="#ffa0a0">'Tarsiiformes'</font> );
<font color="#ffff60">insert</font> <font color="#ffff60">into</font> `infraorder` ( suborder_id, name ) <font color="#ffff60">values</font> ( <font color="#ffa0a0">2</font>, <font color="#ffa0a0">'Simiiformes'</font> );</pre>
<p>Query analysis is done using the <a href="http://dev.mysql.com/doc/refman/5.0/en/explain.html">EXPLAIN</a> statement.  Here&#8217;s an example of how to use it:</p>
<pre>
<font color="#ffff60">explain</font> extended
<font color="#ffff60">select</font> o.name, s.name, i.name
<font color="#ffff60">from</font> `<font color="#ffff60">order</font>` o, suborder s, infraorder i
<font color="#ffff60">where</font> o.id = s.order_id
<font color="#ffff60">and</font> s.id = i.suborder_id
<font color="#ffff60">and</font> i.name = <font color="#ffa0a0">'Simiiformes'</font>;</pre>
<p>The output looks like this:</p>
<pre>
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | o     | ALL  | PRIMARY       | NULL | NULL    | NULL |    1 |             |
|  1 | SIMPLE      | s     | ALL  | PRIMARY       | NULL | NULL    | NULL |    2 | Using where |
|  1 | SIMPLE      | i     | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
3 rows in set, 1 warning (0.01 sec)</pre>
<p>It lists the tables in the order that they are joined in.  The letters in the table column refer to the aliases that I declared in the query.  It reads a row from the first table, then recursively finds a matching row in the second table, the third table, etc &#8230;  In my example here it reads the one row from the order table first, then joins to the suborder table, and finally the infraorder table.  </p>
<p>The &#8216;type&#8217; column is probably the most important piece of data that is returned.  The possible values, from best to worst, are system, const, eq_ref, ref, range, index, all.  As you can see, our test query has returned nothing but &#8216;ALL&#8217;, the worst possible type of join in MySQL.  ALL is basically a sequential scan, the optimizer is planning on reading every row in each table.  </p>
<p>Let&#8217;s add a few indexes and see if we can&#8217;t improve this a little bit:</p>
<pre>
<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_subordid <font color="#ffff60">on</font> infraorder ( suborder_id );
<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_ordid <font color="#ffff60">on</font> suborder ( order_id );</pre>
<pre>
+----+-------------+-------+------+------------------+----------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys    | key      | key_len | ref         | rows | Extra       |
+----+-------------+-------+------+------------------+----------+---------+-------------+------+-------------+
|  1 | SIMPLE      | o     | ALL  | PRIMARY          | NULL     | NULL    | NULL        |    1 |             |
|  1 | SIMPLE      | s     | ref  | PRIMARY,ix_ordid | ix_ordid | 4       | monkey.o.id |    1 |             |
|  1 | SIMPLE      | i     | ALL  | ix_subordid      | NULL     | NULL    | NULL        |    4 | Using where |
+----+-------------+-------+------+------------------+----------+---------+-------------+------+-------------+
3 rows in set, 1 warning (0.00 sec)</pre>
<p>The join on the suborder table is now type &#8216;ref&#8217;.  This is a good thing, it means that the query optimizer has chosen to use our index on the suborder table for every single row that gets returned from the query.  </p>
<p>However, our index on the infraorder table isn&#8217;t being used.  Why?  I&#8217;m not entirely certain.  I assume that it has to do with how little data there is in the table. If that&#8217;s the case, then the query optimizer assumes that returning all rows in order to satisfy the &#8220;i.name = &#8216;Simiiformes&#8217;&#8221; part of the where clause is more efficient than going to ix_subordid, and then only filtering on the names of those rows returned.  </p>
<p>Let&#8217;s drop that index and create a multiple-column index instead:</p>
<pre><font color="#ffff60">drop</font> <font color="#ffff60">index</font> ix_subordid <font color="#ffff60">on</font> infraorder;
<font color="#ffff60">create</font> <font color="#ffff60">index</font> ix_infra <font color="#ffff60">on</font> infraorder ( name, suborder_id );</pre>
<pre>
+----+-------------+-------+------+------------------+----------+---------+-------------------+------+--------------------------+
| id | select_type | table | type | possible_keys    | key      | key_len | ref               | rows | Extra                    |
+----+-------------+-------+------+------------------+----------+---------+-------------------+------+--------------------------+
|  1 | SIMPLE      | o     | ALL  | PRIMARY          | NULL     | NULL    | NULL              |    1 |                          |
|  1 | SIMPLE      | s     | ref  | PRIMARY,ix_ordid | ix_ordid | 4       | monkey.o.id       |    1 |                          |
|  1 | SIMPLE      | i     | ref  | ix_infra         | ix_infra | 26      | const,monkey.s.id |    2 | Using where; Using index |
+----+-------------+-------+------+------------------+----------+---------+-------------------+------+--------------------------+
3 rows in set, 1 warning (0.00 sec)</pre>
<p>Now we&#8217;re using both the indexes in both of those tables.  There&#8217;s an important caveat to using a <a href="http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html">multiple-column index</a> though.  In the example that I&#8217;ve created here, if I were to construct and execute a query on the infraorder table that referenced the name column but not the suborder_id, it would still use the index.  The opposite is not true.  </p>
<p>If you have a multiple-column index that has 3 columns, let&#8217;s call them A, B, and C.  If your query uses all three, A and B, or just A, it can still utilize the index.  If it uses just B, or just C, or B and C, it can&#8217;t.  If it refers to A and C, then it will use the index for column A, but it will have to filter out the results that don&#8217;t match column C.  </p>
<p>I hope that makes sense.  I can&#8217;t think of any clearer way to explain the concept.  </p>
<p>There are a few rules of thumb when it comes to indexes.  These are almost universal, they don&#8217;t just apply to MySQL.  First of all, you want an index that has short keys.  This refers to the key_len column when we do an explain.  The shorter the keys, the higher the number that will be read from the disk in each block.  Another benefit is it means more of the index will be cached in memory.  </p>
<p>Another rule of thumb is that you want your indexes to be as unique as possible.  If you are indexing a column, you have a 100,000 rows in the table, and the column is comprised of four unique values, then your index isn&#8217;t much use.  </p>
<p>MySQL supports indexing only part of the field.  So, if you have a varchar(200), and the majority of the entries in the column are unique across the first 10 characters, you can index just those first 10 characters.  Now, instead of using 200 characters for each key in the index, it only uses 10.  </p>
<p>There is overhead associated with indexes.  As a result, you should add them sparingly.  This is especially true if you require any sort of performance when it comes to data modification queries (insert, update, delete).  You don&#8217;t just have to modify the data, the indexes have to be modified as well.  </p>
<p>What do you gain from using multiple-column indexes?  They are more unique, and MySQL will favor the index that the query plan assumes will return the fewest number of rows.  Another really cool thing, and most databases do this, if an index has all of the data necessary to return the answer without consulting the data, then the engine will use just the index.  Examples are queries where you are trying to find a count of rows, a min or a max, etc &#8230; These are called covered queries and there are more possibilities if your index refers to more columns.  Don&#8217;t go listing all the columns though.  Then you just end up duplicating the table in the index space.  Remember, small keys.  </p>
<p>Two other things before I go to bed.  I keep mentioning the query optimizer.  Optimizer&#8217;s are a fascinating subject.  They rely on statistical information about the database in order to make an educated guess about how to execute the query.  The &#8216;<a href="http://dev.mysql.com/doc/refman/5.0/en/analyze-table.html">ANALYZE TABLE</a>&#8216; command analyzes the table and stores the key distribution information that the optimizer uses to make some of those decisions.  It needs to be run periodically, in some cases frequently, in order for the optimizer to function properly.  </p>
<p>Another important statement is &#8216;<a href="http://dev.mysql.com/doc/refman/5.0/en/table-optimization.html">OPTIMIZE TABLE</a>&#8216;.   If you use varchar, or any other variable length data type, then deleting data fragments your table.  The OPTIMIZE command is a defragmenter for your database.  It also sorts the index keys, which can improve performance.  </p>
<p>Wow &#8230; sleepy now.  If you are in the market for an effective sedative, then I recommend reading the <a href="http://dev.mysql.com/doc/refman/5.0/en/">MySQL 5.0 Reference Manual</a>. <img src='http://www.boyplankton.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.boyplankton.com/2007/03/25/mysql-indexes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.434 seconds -->
