Индексът ще трябва да покрива цялата част от заявката (част за равенство, част за сортиране и част от диапазон). Това е така, защото в типичен find()
заявка, MongoDB използва само един индекс. Например, обикновено не използва един индекс за частта за равенство и друг индекс за частта за сортиране.
Като цяло последователността от полета в индекса трябва да следва модела на равенство -> сортиране -> диапазон .
Това е описано подробно в Оптимизиране на MongoDB съставни индекси .
За вашата заявка частта за равенство е tag:..., letterId:...
и частта за сортиране е emailId:-1
. Във вашата заявка няма част от диапазон.
Използвайки този модел, съставният индекс, от който се нуждаете, е:
db.test.createIndex({tag:1, letterId:1, emailId:-1})
Нека се опитаме да потвърдим какво подобрение на производителността можем да постигнем с помощта на този индекс.
Данни от теста
За да потвърдя пригодността на индекса, вмъкнах 1 милион записа в тестова база данни с помощта на mgeneratejs , който е инструмент за създаване на случаен документ с помощта на шаблон.
Въз основа на вашия пример, mgeneratejs
шаблонът, който използвам, е:
$ cat template.json
{
"emailId": "$hash",
"email": "$email",
"letterId": "$hash",
"sendedFrom": "$email",
"resultMsg": "$word",
"owner": "$name",
"created": "$date",
"result": "$bool",
"tag": "$word",
"tryNum": {"$integer": {"min": 0, "max": 1e3}},
"clickHash": "$word",
"links": {"$array": {"of": "$url", "number": {"$integer": {"min": 1, "max": 5}}}}
}
и импортира 1 милион произволни документа в MongoDB:
$ mgeneratejs template.json -n 1000000 | mongoimport -d test -c test
Тест 1:неоптимален индекс
След това създадох индекса, който имате, и се опитах да намеря несъществуващ документ и събрах 10 изпълнения на заявката с колекция, съдържаща само този индекс:
> db.test.createIndex({emailId: 1, letterId: 1, result: 1, owner: 1, tag: 1, clickHash: 1})
> db.test.find({"tag" : "xyz", "letterId" : "abc"}).sort({emailId: -1}).limit(1)
Fetched 0 record(s) in 3069ms
Fetched 0 record(s) in 2924ms
Fetched 0 record(s) in 2923ms
Fetched 0 record(s) in 3013ms
Fetched 0 record(s) in 2917ms
Fetched 0 record(s) in 2961ms
Fetched 0 record(s) in 2882ms
Fetched 0 record(s) in 2870ms
Fetched 0 record(s) in 2969ms
Fetched 0 record(s) in 2863ms
така че използвайки този индекс, времето за отговор на заявката не е голямо, като повечето изпълнение е близо до 3 секунди.
Тест 2:равенство -> сортиране -> индекс на диапазон
Чрез добавяне на оптималното равенство -> сортиране -> диапазон индекс:
> db.test.createIndex({tag:1, letterId:1, emailId:-1})
> db.test.find({"tag" : "xyz", "letterId" : "abc"}).sort({emailId: -1}).limit(1)
Fetched 0 record(s) in 2ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 3ms
За разлика от това, използвайки оптималния индекс, производителността беше значително подобрена. Нито една заявка не се връща за повече от 3 ms, като по-голямата част от времето се връща за 1 ms.