Advanced Schema Patterns and Antipatterns / Identify Advanced Antipatterns
MongoDB indexes are required to support fast queries. During the development of our bookstore app, we added indexes indiscriminately. But recently, our performance has been poor. Could this be related to our indexing strategy?
In this video, we'll discuss how to identify and address the unnecessary indexes antipattern. While you may assume that you need to create an index for every query, this can result in unnecessary indexes. As a result, you could experience a reduced performance. An index is unnecessary when it's not used, rarely used, or covered by another compound index.
While the limit for the number of indexes per collection is 64, we recommend using the fewest number of indexes possible to efficiently support application queries. Indexes require space and need to be loaded in memory when used. As the collection grows, so do indexes. Unnecessary indexes can negatively impact write performance because indexes must be updated every time a document is created, updated, or deleted.
Let's take a look at an example from our bookstore application to learn more. We initially indexed every field used in a query on the book collection and created a compound index on title and author. However, opening new pages and adding new books is slow in the app. Slow queries and write operations are two indicators of suboptimal indexing strategy.
Let's see what's going on. We can use an aggregation pipeline with $indexStats stage to measure index use for a collection. Let's add a project stage to limit the output. In this case, we are only interested in the index name, ops, or the number of times an index has been accessed by a user request, and since, which defines the time period.
Finally, we can use sort stage to sort indexes by users in ascending order. This way, least used indexes are displayed first. Our app is running on an Atlas M10 cluster. So we can use the Data Explorer and Performance Advisor to check our indexes.
Please note that Performance Advisor is only available for M10 and above clusters. Let's use the Atlas Data Explorer to check index usage for the Books collection. Here, we can see our application frequently uses a compound index on title and author along with indexes on author, rating, and title fields. If we start again to reverse the order, we can see that the indexes on price, pages, year, and genre fields are not active.
Reviewing the used indexes in more detail, the index on title is redundant because title is covered by the compound index on title and author. If you haven't already or simply need a refresher, check out our content on indexes to learn more about how to efficiently arrange index keys in a compound index. Luckily, the Atlas Performance Advisor will highlight redundant indexes for us. This is a clear example of the unnecessary indexes antipattern.
Several indexes are not being used, but they take space. And they need to be updated when the documents including those fields change. Once we have confirmed which indexes are unnecessary, we need to drop these indexes in order to restore the app performance. Remember that the index on the _id is required and cannot be dropped.
Before dropping an index, we recommend hiding it with the hideIndex method. This lets you evaluate the impact on your app before the actual removal. If the app isn't negatively impacted by removing the index, we can call the dropIndex function to permanently remove the unnecessary index. We can also drop indexes with the Atlas Data Explorer.
Here, we press the Drop Index button on the Action column for desired indexes. Then we enter the name of the index when prompted and confirm the action. Let's recap what we've learned in this video. Creating indexes that support your queries is important.
But unnecessary indexes take up resources and reduce performance. An index is unnecessary if it's not used or if it's redundant because another compound index covers it. You can discover and remove unnecessary indexes with Atlas Data Explorer, Performance Advisor, or the $indexStats aggregation stage. You can also hide indexes with hideIndex or remove them with the dropIndex.
Great work. See you in the next lesson.
