MongoDB — The Judgement Behind Document Databases
The Reason It Is Slow Is Usually the Index
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.
- Finding by
statusalone — usable. - Finding by
statusand sorting bycreatedAt— usable. The sort becomes free. - Finding by
createdAtalone — not usable. The leading part is missing.
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.