<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Moves On Rails: Tag indexes</title>
    <link>http://www.movesonrails.com/articles/tag/indexes?tag=indexes</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>New ways to look at software</description>
    <item>
      <title>Optimizing the queries of your rails app</title>
      <description>&lt;p&gt;When you are developing your application, you should allways look for the following line in your development console.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Processing EmployeesController#index[GET]
Employee Load (0.055003) 
SELECT * FROM `people` WHERE `people`.`type` = 'Employee'

 select_type | key_len | type | Extra       |
---------------------------------------------  =&amp;gt;
 SIMPLE      |         | ALL  | Using where |

| id | possible_keys | rows | table  | ref | key
--------------------------------------------------
| 1  |               | 6965 | people |     |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The type ALL means that you are preforming a full table scan in a query. This is usually not a problem when you are in development mode, but what is you have millions of people in your database?&lt;/p&gt;

&lt;p&gt;Usually it is pretty straight forward to find out where you were calling this from, as you will probably remember what the request was you did. If you are having a hard time, install the query_trace plugin. This gives the following result:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;vendor/plugins/query_analyzer/lib/query_analyzer.rb:38:in `select'
app/controllers/employees_controller.rb:71:in `find'
app/controllers/employees_controller.rb:71:in `index'
vendor/plugins/browser-prof/lib/browser-prof.rb:32:in `process'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking at line 71 of the employees controller is a good idea here as you might be doing something stupid. As line 71 just reads: @employees = Employee.find(:all)) we have to turn to your database.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql -u root --database myapp_development

mysql&amp;gt; EXPLAIN SELECT * FROM `people` WHERE `people`.`type` = 'Employee';
+----+-------------+--------+------+------------------+
| id | select_type | table  | type | possible_keys    |
+----+-------------+--------+------+------------------+ =&amp;gt;
|  1 | SIMPLE      | people | ALL  |                  |
+----+-------------+--------+------+------------------+

+------+---------+------+------+-------------+
| key  | key_len | ref  | rows | Extra       |
+------+---------+------+------+-------------+
| NULL | NULL    | NULL | 6873 | Using where |
+---------+------+------+------+-------------+
1 row in set (0.00 sec)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see we are not hitting any indexes. Lets try adding an index.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; create index people_type_test on people (type);
Query OK, 6715 rows affected (1.38 sec)
Records: 6715  Duplicates: 0  Warnings: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we run the explain again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; EXPLAIN SELECT * FROM `people` WHERE `people`.`type` = 'Employee' ;
+----+-------------+--------+------+------------------+
| id | select_type | table  | type | possible_keys    |
+----+-------------+--------+------+------------------+ =&amp;gt;
|  1 | SIMPLE      | people |range | people_type_test |
+----+-------------+--------+------+------------------+

+------------------+---------+-------+------+-------------+
| key              | key_len | ref   | rows | Extra       |
+------------------+---------+-------+------+-------------+
| people_type_test | 768     | const | 2496 | Using where |
+------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thats more like it, now we need to add this to our app trough a migration.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class CreatePeopleIndices &amp;lt; ActiveRecord::Migration
  def self.up
    add_index :people, :type
  end

  def self.down
    remove_index :people, :type    
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After a db:migrate and a restart of the server, we now see the following in the development console:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Employee Load (0.027666)
SELECT * FROM `people` WHERE `people`.`type` = 'Employee'
Analyzing Employee Load

 select_type | key_len | type | Extra       |
---------------------------------------------  =&amp;gt;
 SIMPLE      | 768     | ref  | Using where |

| id | possible_keys        | rows | table  | ref   | key
----------------------------------------------------------------------
| 1  | index_people_on_type | 2496 | people | const | people_type_test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Success! Also note that the load on the database has been cut in half.&lt;/p&gt;</description>
      <pubDate>Wed, 09 Apr 2008 21:47:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:a4f47013-7652-428a-819b-32ba4474e97f</guid>
      <author>bart.tenbrinke@movesonrails.com (Bart ten Brinke)</author>
      <link>http://www.movesonrails.com/articles/2008/04/09/optimizing-the-queries-of-your-rails-app</link>
      <category>Rails</category>
      <category>indexes</category>
      <category>database</category>
      <category>mysql</category>
      <category>slow</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
