TT Lab
Get started
Learn Learning paths Courses

MongoDB — The Judgement Behind Document Databases

The Reason It Is Slow Is Usually the Index

Continue in TT Lab

In one line

Without an index, a document database also scans everything. It is written as COLLSCAN. It is exactly the same as an RDB's Seq Scan, and the remedy is the same.

Why it is needed — the reason it is slow is usually one

Most reports that "MongoDB is slow" are not about the database but about queries without an index. With ten thousand documents, nobody notices. At a million, the same code suddenly becomes slow, and that is when people suspect the database.

The way to check is the same as in an RDB. Ask for the plan.

db.items.find({ name: "빨간 배낭" }).explain()

There are only two words to look for in the plan. COLLSCAN means everything was scanned, and IXSCAN means an index was used.

Look at the numbers too

The stage name alone is only half the story. With explain('executionStats') you get how many documents were actually scanned.

Value Meaning
nReturned The number of documents actually returned
totalDocsExamined The number of documents opened to find them

The ratio of these two is the index's report card. If it opened a million documents to return one, the index is missing or set up wrongly. Conversely, if the two are close, it is set up well.

For a compound index, the order is everything

Once you decide to create an index, the next question is in what order to combine the fields. The compound index of a document DB is also a structure sorted by value, so it can be used from the leading field onward, and that rule decides what it can and cannot use.

An index created as { status: 1, createdAt: -1 } is used like this.

A picture of a compound index sorted by status ascending and then createdAt descending being scanned by three kinds of lookups. When finding by status, the matching entries sit together, so only one contiguous range is scanned, and adding a sort is free because it is already in descending order. When finding by createdAt alone, the matching entries are scattered and there is no contiguous range

From this comes the practical ordering rule. Put fields filtered by equality first, and fields filtered by range or used for sorting after them. A field placed after a field with a range condition cannot be used for seeking and is used only for filtering.

If a sort cannot use the index, it quietly becomes expensive. A document DB sorts in memory, and there is a limit on that amount; if you exceed it, it fails with an error or uses temporary files. What especially surprises people is that even with few results, it gets stuck if there are many candidates before the sort. If you see a separate sort stage in the plan, check whether that order can be moved into the index.

An index on an array field is different in nature. One entry is created per array element, so a single document enters the index many times. If you index an array with hundreds of elements, the index grows by that much and writes get slower. And you cannot combine two or more array fields in one index. The number of combinations multiplies and explodes.

Finally, if all the values needed are inside the index, the documents are not opened at all. This is when the totalDocsExamined you saw earlier becomes 0, and it is especially valuable for reads that show only a few fields, such as a list screen.

In the field

Creating more indexes is not always the answer. An index slows down writes and takes up space. Every time you insert a document, all the indexes are updated.

So there is an order. First read the plan to confirm what is slow, and then create an index for that one query. An index created "just in case" often leaves only the write cost behind and makes no query faster.

Whether you keep to this order is the point where answers diverge in an interview that asks about SQL optimization experience.