<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Indexes on Jason Wilder&#39;s Blog</title>
        <generator uri="https://gohugo.io">Hugo</generator>
        <link>http://jasonwilder.com/categories/indexes/</link>
        
        <language>en-us</language>  
        <updated>Wed, 08 Feb 2012 00:00:00 UTC</updated>
        
        <item>
            <title>Optimizing MongoDB Indexes</title>
            <link>http://jasonwilder.com/blog/2012/02/08/optimizing-mongodb-indexes/</link>
            <pubDate>Wed, 08 Feb 2012 00:00:00 UTC</pubDate>
            
            <guid>http://jasonwilder.com/blog/2012/02/08/optimizing-mongodb-indexes/</guid>
            <description>

&lt;p&gt;Good indexes are an important part running a well performing application on MongoDB.  MongoDB performs best
when it can keep your indexes in RAM.  Reducing the size of your indexes also leads to faster queries and the
ability to manage more data with less RAM.&lt;/p&gt;

&lt;p&gt;These are a few tips to reduce the size of your MongoDB indexes:&lt;/p&gt;

&lt;h3 id=&#34;1-determining-indexes-sizes:6767c783482562a5eb48fdd85b43cdd8&#34;&gt;1) Determining Indexes Sizes&lt;/h3&gt;

&lt;p&gt;The first thing you should do is to understand the size of your indexes.  You want to know the sizes before
you make changes to confirm that the changes have actually reduced the size.  Ideally, you are graphing
your indexes over time with your monitoring tools.&lt;/p&gt;

&lt;p&gt;Using the mongo shell you can run db.stats() to get database indexes stats:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; db.stats()
{
	&amp;quot;db&amp;quot; : &amp;quot;examples1&amp;quot;,
	&amp;quot;collections&amp;quot; : 6,
	&amp;quot;objects&amp;quot; : 403787,
	&amp;quot;avgObjSize&amp;quot; : 121.9966467469235,
	&amp;quot;dataSize&amp;quot; : 49260660,
	&amp;quot;storageSize&amp;quot; : 66695168,
	&amp;quot;numExtents&amp;quot; : 20,
	&amp;quot;indexes&amp;quot; : 9,
	&amp;quot;indexSize&amp;quot; : 48524560,
	&amp;quot;fileSize&amp;quot; : 520093696,
	&amp;quot;nsSizeMB&amp;quot; : 16,
	&amp;quot;ok&amp;quot; : 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;indexes - The number of indexes in examples1 DB&lt;/li&gt;
&lt;li&gt;indexSize - The size of the indexes in example1 DB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since each collection has indexes, you can run db.collection.stats() to see them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; db.address.stats()
{
	&amp;quot;ns&amp;quot; : &amp;quot;examples1.address&amp;quot;,
	&amp;quot;count&amp;quot; : 3,
	&amp;quot;size&amp;quot; : 276,
	&amp;quot;avgObjSize&amp;quot; : 92,
	&amp;quot;storageSize&amp;quot; : 8192,
	&amp;quot;numExtents&amp;quot; : 1,
	&amp;quot;nindexes&amp;quot; : 2,
	&amp;quot;lastExtentSize&amp;quot; : 8192,
	&amp;quot;paddingFactor&amp;quot; : 1,
	&amp;quot;flags&amp;quot; : 1,
	&amp;quot;totalIndexSize&amp;quot; : 16352,
	&amp;quot;indexSizes&amp;quot; : {
		&amp;quot;_id_&amp;quot; : 8176,
		&amp;quot;_types_1&amp;quot; : 8176
	},
	&amp;quot;ok&amp;quot; : 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;totalIndexSize - The size of all indexes in the collection&lt;/li&gt;
&lt;li&gt;indexSizes - A dictionary of index name and size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;NOTE: all sizes returned by these commands are in bytes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These commands are useful but they are tedious to use manually.  To report on indexes stats, I wrote a
utility, index-stats.py, that can be found in the
&lt;a href=&#34;https://github.com/jwilder/mongodb-tools&#34;&gt;mongodb-tools&lt;/a&gt; project on Github that makes things
easier.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(virtualenv) mongodb-tools$ ./index-stats.py
Checking DB: examples2.system.indexes
Checking DB: examples2.things
Checking DB: examples1.system.indexes
Checking DB: examples1.address
Checking DB: examples1.typeless_address
Checking DB: examples1.user
Checking DB: examples1.typeless_user

Index Overview
+----------------------------+------------------------+--------+------------+
|         Collection         |         Index          | % Size | Index Size |
+----------------------------+------------------------+--------+------------+
| examples1.address          | _id_                   |   0.0% |      7.98K |
| examples1.address          | _types_1               |   0.0% |      7.98K |
| examples1.typeless_address | _id_                   |   0.0% |      7.98K |
| examples1.typeless_user    | _id_                   |  10.1% |      6.21M |
| examples1.typeless_user    | address_id_1           |  10.1% |      6.21M |
| examples1.typeless_user    | typeless_address_ref_1 |   5.9% |      3.62M |
| examples1.user             | _id_                   |  10.1% |      6.21M |
| examples1.user             | _types_1               |   6.9% |      4.24M |
| examples1.user             | _types_1_address_id_1  |  12.2% |      7.51M |
| examples1.user             | _types_1_address_ref_1 |  26.2% |     16.09M |
| examples2.things           | _id_                   |  10.1% |      6.21M |
| examples2.things           | _types_1               |   8.4% |      5.13M |
+----------------------------+------------------------+--------+------------+

Top 5 Largest Indexes
+-------------------------+------------------------+--------+------------+
|        Collection       |         Index          | % Size | Index Size |
+-------------------------+------------------------+--------+------------+
| examples1.user          | _types_1_address_ref_1 |  26.2% |     16.09M |
| examples1.user          | _types_1_address_id_1  |  12.2% |      7.51M |
| examples1.typeless_user | _id_                   |  10.1% |      6.21M |
| examples2.things        | _types_1               |   8.4% |      5.13M |
| examples1.user          | _types_1               |   6.9% |      4.24M |
+-------------------------+------------------------+--------+------------+

Total Documents: 600016
Total Data Size: 74.77M
Total Index Size: 61.43M
RAM Headroom: 2.84G
Available RAM Headroom: 1.04G
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output shows the total index size, each index size, and their relative sizes to each other.
In addition, the Top 5 Largest indexes are reported across all your collections.
This makes it easy to determine your largest indexes and the ones where reducing
their size will provide most benefit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAM Headroom is your physical memory - index size.  A positive value means you have RAM available for indexes to fit
in memory.&lt;/li&gt;
&lt;li&gt;Available RAM Headroom is free memory - index size.  Since other processes consume memory on this system, I don&amp;rsquo;t
have the total RAM Headroom available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The RAM Headroom stat idea comes from the
&lt;a href=&#34;http://blog.boxedice.com/2011/02/15/mongodb-monitoring-dashboard/&#34;&gt;MongoDB monitoring service&lt;/a&gt; I use,
&lt;a href=&#34;http://serverdensity.com&#34;&gt;ServerDensity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From this output, I would focus on the examples1.user collection and the &lt;em&gt;types_1_address_ref_1&lt;/em&gt; and
&lt;em&gt;types_1_address_id_1&lt;/em&gt; indexes first.&lt;/p&gt;

&lt;h3 id=&#34;2-remove-redundant-indexes:6767c783482562a5eb48fdd85b43cdd8&#34;&gt;2) Remove Redundant Indexes&lt;/h3&gt;

&lt;p&gt;If you have been releasing code changes over a period of time, you&amp;rsquo;ll likely end up with redundant indexes.  MongoDB
can use the prefix of a compound index if all the component parts are not available.  In the previous output,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;| examples1.user          | _types_1               |   6.9% |      4.24M |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is redundant with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;| examples1.user          | _types_1_address_ref_1 |  26.2% |     16.09M |
| examples1.user          | _types_1_address_id_1  |  12.2% |      7.51M |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because _&lt;em&gt;types_1&lt;/em&gt; is the prefix to these two indexes. Dropping it would save 4.2M on the total index
size and be one less index to update when user documents change.&lt;/p&gt;

&lt;p&gt;To make it easier to find these indexes, you can run redundant-indexes.py from
&lt;a href=&#34;https://github.com/jwilder/mongodb-tools&#34;&gt;mongodb-tools&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(virtualenv)mongodb-tools$ ./redundant-indexes.py
Checking DB: examples2
Checking DB: examples1
Index examples1.user[_types_1] may be redundant with examples1.user[_types_1_address_ref_1]
Index examples1.user[_types_1] may be redundant with examples1.user[_types_1_address_id_1]
Checking DB: local
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;3-compact-command:6767c783482562a5eb48fdd85b43cdd8&#34;&gt;3) Compact Command&lt;/h3&gt;

&lt;p&gt;If you are running MongoDB 2.0+, you can run the compact command to defragment your collections and rebuild
the indexes.  The compact command locks the database so make sure you know where you are running it beforehand.
If you are running with replica sets, the easiest thing to do is to run it on your secondaries, one at a time, fail-over
the primary to new secondary and run compact on the old primary.&lt;/p&gt;

&lt;h3 id=&#34;4-mongodb-2-0-index-improvements:6767c783482562a5eb48fdd85b43cdd8&#34;&gt;4) MongoDB 2.0 Index Improvements&lt;/h3&gt;

&lt;p&gt;If you are not running MongoDB 2.0 or later, upgrading and rebuilding your indexes should provide about a
25% savings.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&#34;http://www.mongodb.org/display/DOCS/2.0+Release+Notes#2.0ReleaseNotes-IndexPerformanceEnhancements&#34;&gt;Index Performance Enhancements&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;5-check-index-criteria:6767c783482562a5eb48fdd85b43cdd8&#34;&gt;5) Check Index Criteria&lt;/h3&gt;

&lt;p&gt;Another thing to check is your index criteria.  You want the values that are indexed to be small and as selective
as possible.  Indexing values that do not help MongoDB find
your data faster slow queries down and increase the index size.  If you are using a mapping framework for your
application, and it support defining indexes in the code, you should
check to see what it&amp;rsquo;s actually indexing.  For example &lt;a href=&#34;http://mongoengine.org/&#34;&gt;MongoEngine&lt;/a&gt; for Python
uses a &amp;ldquo;_types&amp;rdquo; field to identify subclasses in the same collection.  This can add a lot of space and may not add
to the selectivity of you indexes.&lt;/p&gt;

&lt;p&gt;In my test data, my largest index is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;| examples1.user             | _types_1_address_ref_1 |  26.2% |     16.09M |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking at the data for it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; db.user.findOne()
{
	&amp;quot;_id&amp;quot; : ObjectId(&amp;quot;4f2ef95c89a40a11c5000002&amp;quot;),
	&amp;quot;_types&amp;quot; : [
		&amp;quot;User&amp;quot;
	],
	&amp;quot;address_id&amp;quot; : ObjectId(&amp;quot;4f2ef95c89a40a11c5000000&amp;quot;),
	&amp;quot;address_ref&amp;quot; : {
		&amp;quot;$ref&amp;quot; : &amp;quot;address&amp;quot;,
		&amp;quot;$id&amp;quot; : ObjectId(&amp;quot;4f2ef95c89a40a11c5000000&amp;quot;)
	},
	&amp;quot;_cls&amp;quot; : &amp;quot;User&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that &lt;em&gt;_types&lt;/em&gt; is an array with a value of &lt;em&gt;User&lt;/em&gt;, the class name.  Since I don&amp;rsquo;t have any subclasses of &lt;em&gt;User&lt;/em&gt;
in my code, indexing this value does not help the index selectivity. Another way of thinking about this is that each
value in the index is going to have &amp;ldquo;User&amp;rdquo; as a prefix which adds a few extra bytes for value and does not increase
the selectivity of the index.&lt;/p&gt;

&lt;p&gt;Removing it in the code with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class User(Document):
    meta {&#39;index_types&#39;:False}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Changes the index to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;| examples1.user             | address_ref_1          |  16.8% |     12.39M |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;About a 23% savings.&lt;/p&gt;

&lt;p&gt;Digging in further, &lt;em&gt;address_ref_1&lt;/em&gt; is a &lt;em&gt;ReferenceProperty&lt;/em&gt; to an &lt;em&gt;Address&lt;/em&gt; object.  The data above shows that it is a
dictionary that contains the id of the reference field as well as the collection that it points to.  If we
change this &lt;em&gt;ReferenceProperty&lt;/em&gt; to an &lt;em&gt;ObjectIdProperty&lt;/em&gt;, which is what &lt;em&gt;address_id&lt;/em&gt;, is, you can get additional savings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;| examples1.user             | address_id_1           |   9.5% |      6.21M |
| examples1.user             | address_ref_1          |  20.9% |     13.70M |

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;About a 53% savings.  This changes the index value from being stored as a serialized dictionary to just and ObjectId
which is likely highly optimized with MongoDB.  Changing the property type does require code changes though and
you also lose the automatic de-referencing capability provided by &lt;em&gt;ReferenceProperties&lt;/em&gt;. It can produce significant
savings though.&lt;/p&gt;

&lt;p&gt;In total, we&amp;rsquo;ve reduced the original index by 61% by adjusting some index criteria and making some small code changes.&lt;/p&gt;

&lt;h3 id=&#34;6-delete-move-old-data:6767c783482562a5eb48fdd85b43cdd8&#34;&gt;6) Delete/Move Old Data&lt;/h3&gt;

&lt;p&gt;In most applications, some data is accessed more frequently than others.  If you have old data that won&amp;rsquo;t be accessed
by your users, you may be able to purge it, move it to another un-indexed collection, or archive it somewhere outside
of the DB.  Ideally, you database contains and is indexing the working set of available data.&lt;/p&gt;

&lt;p&gt;There are some other good optimization ideas that can be found here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.slideshare.net/andrew311/optimizing-mongodb-lessons-learned-at-localytics&#34;&gt;Optimizing MongoDB: Lessons Learned at Localytics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.scribd.com/doc/56271132/MongoDB-Performance-Tuning&#34;&gt;MongoDB Performance Tuning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you tune your indexes?&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
