Понимание индекса MongoDB
Индекс MongoDB: глубокое погружение, понимание индексов.
Повышение производительности за счет оптимального использования индексов за счет понимания структуры данных, того, как они работают / хранятся, как загружаются в память. Как оптимизация запросов принимает решение о выборе индексов.
Требуется базовое понимание индексов, т.е. что такое индексы, типы индексов, их создание. Https://docs.mongodb.com/manual/indexes/
- Структура данных
- Хранение на диске
- Выделение памяти.
Структура данных
Индекс в поле / полях сохраняется в порядке, который мы указываем с помощью структуры данных B-Tree. Сохранено в порядке. Посмотрим, что это означает и чем помогает.
- Индекс создается на основе значения поля, относящегося к фактическому сохраненному документу.
- Использование индексов B-Tree значительно сокращает количество сравнений для поиска документа.
- Аналогично на рисунке ниже мы видим, что с индексом (голубая линия) даже добавление документа все еще ограничивает количество проверяемых документов по сравнению с без индекса / сканирования.
Хранилище на диске
Давайте посмотрим / визуализируем, как индекс хранится на диске. Индекс, хранящийся на диске, управляется самим механизмом хранения базы данных.
- Использует сжатие индекса префикса. Повторяющееся значение префикса не записывается. Давайте посмотрим на примере, чтобы понять, что оно означает.
db.getCollection("movieTicket") .ensureIndex({"showDate":1, "seatNo":1, "status":1});
Как индекс ({«showDate»: 1, «seatNo»: 1, «status»: 1}) сохраняется на диске.
Как индекс ({«seatNo»: 1, «showDate»: 1, «status»: 1}) сохраняется на диске.
Размер составного индекса может варьироваться в зависимости от положения поля индекса (плотское / избирательное).
Индекс: «seatNostorage.wiredTiger.engineConfig.cacheSizeGB
showDatestorage.wiredTiger.engineConfig.cacheSizeGB
status_1» займет больше места, чем index: «showDatestorage.wiredTiger.engineConfig.cacheSizeGB
seatNostorage.wiredTiger.engineConfig.cacheSizeGB
status_1 ».
Приведенный выше пример помогает понять, как работает сжатие префиксов, а не предполагает, что это критерий для выбора индекса.
- Параллельные операции ввода-вывода путем сохранения индексов в отдельном подкаталоге, который может быть связан с другим диском.
Запустите сервер mongd с параметром --wiredTigerDirectoryForIndexes.
см .: https: // docs.mongodb.com/manual/reference/program/mongod/#cmdoption-mongod-wiredtigerdirectoryforindexes
Выделение памяти
Индексы работают лучше всего, когда они могут уместиться в памяти, но что, если это не так, и можем ли мы все же оптимизировать их, понимая, как работает распределение памяти для индексов.
Под памятью здесь подразумевается выделенная для MongoDB память, а не общий объем ОЗУ / памяти на машине.
Чтобы настроить размер внутреннего кеша WiredTiger, см.storage.wiredTiger.engineConfig.cacheSizeGB
и--wiredTigerCacheSizeGB
. Избегайте увеличения размера внутреннего кэша WiredTiger выше значения по умолчанию.
//To find Internal memory allocated to wiredTiger.cache db.serverStatus().wiredTiger.cache ; "maximum bytes configured" : 16586375168 //Find the system memory db.hostInfo(); { "system" : { .. "memSizeMB" : 32660, "memLimitMB" : 32660, "numCores" : 8, .... }, ... }
В лучшем случае индекс полностью помещается в память
Но на тот случай, если не влезет в память.
Затем проиндексированные страницы просматриваются, из них удаляются из памяти, а самые свежие загружаются в память.
В сценарии, когда в используемом индексе происходит непрерывный обход, то есть ключ индекса распределяется по всем страницам для значения поля, в котором выполняется запрос. [Индекс не полностью помещается в память].
Это приведет к большому количеству страниц ввода / вывода с использованием Disk I / 0, что сильно повлияет на производительность запроса / индекса. [см. рисунок ниже]
Ex- для запроса ниже.
Используйте подсказку с запросом, что приведет к принудительному использованию индекса по вашему выбору.
db.movieTicket.find({"showDate":"", "seatNo": {$in: ['A1', 'A2', 'A3', 'A4']}}).hint({"showDate": 1, "seatNo": 1, "status": 1});
Отдельная страница будет считана в память.
db.movieTicket.find({"showDate":"", "seatNo": {$in: ['A1', 'A2', 'A3', 'A4']}}).hint({"seatNo": 1, "showDate": 1, "status": 1});
В память будут прочитаны несколько страниц.
Чтобы проверить, нет ли информации, связанной с удаленными прочитанными проиндексированными кэшированными страницами.
// DB stats with indexDetails gives lot's of detailed information. var stats = db.movieTicket.stats({indexDetails:true}); // will just look for cache Information stats.indexDetails.showDatestorage.wiredTiger.engineConfig.cacheSizeGB
seatNostorage.wiredTiger.engineConfig.cacheSizeGB
status_1.cache; stats.indexDetails.seatNostorage.wiredTiger.engineConfig.cacheSizeGB
showDatestorage.wiredTiger.engineConfig.cacheSizeGB
status_1.cache; // OUTPUT - { "bytes currently in the cache" : 210148, "bytes dirty in the cache cumulative" : 0, "bytes read into cache" : 79139, "bytes written from cache" : 0, "checkpoint blocked page eviction" : 0, "data source pages selected for eviction unable to be evicted" : 0, "eviction walk passes of a file" : 0, "eviction walk target pages histogram - 0-9" : 0, "eviction walk target pages histogram - 10-31" : 0, "eviction walk target pages histogram - 128 and higher" : 0, "eviction walk target pages histogram - 32-63" : 0, "eviction walk target pages histogram - 64-128" : 0, "eviction walks abandoned" : 0, "eviction walks gave up because they restarted their walk twice" : 0, "eviction walks gave up because they saw too many pages and found no candidates" : 0, "eviction walks gave up because they saw too many pages and found too few candidates" : 0, "eviction walks reached end of tree" : 0, "eviction walks started from root of tree" : 0, "eviction walks started from saved location in tree" : 0, "hazard pointer blocked page eviction" : 0, "in-memory page passed criteria to be split" : 0, "in-memory page splits" : 0, "internal pages evicted" : 0, "internal pages split during eviction" : 0, "leaf pages split during eviction" : 0, "modified pages evicted" : 0, "overflow pages read into cache" : 0, "page split during eviction deepened the tree" : 0, "page written requiring cache overflow records" : 0, "pages read into cache" : 6, "pages read into cache after truncate" : 0, "pages read into cache after truncate in prepare state" : 0, "pages read into cache requiring cache overflow entries" : 0, "pages requested from the cache" : 70, "pages seen by eviction walk" : 0, "pages written from cache" : 0, "pages written requiring in-memory restoration" : 0, "tracked dirty bytes in the cache" : 0, "unmodified pages evicted" : 0 }
По мере того, как больше страниц будет считываться в память и вытесняться / сбрасываться из памяти, что потребует чтения с диска, что приведет к снижению производительности.
Ссылки:
Понимая, как структурирован индекс, хранится на диске и загружается в память для создания более оптимизированных индексов, при выборе индекса появляется еще много решающих факторов. Надеюсь, это будет полезно, поделитесь своими мыслями.
Удачного индексирования, спасибо :)