Эффективная индексация коллекции электронных писем для заказа и фильтрации по почтовому домену - PullRequest
4 голосов
/ 06 января 2020

Я использую Mon goose для хранения центральной коллекции адресов электронной почты, а также у меня есть коллекции для пользователей и организаций. В моем приложении я связываю пользователей с организациями через их (проверенные) почтовые домены. Например, Acme Ltd владеет доменами acme.com и acme.co.uk, и, выбирая из всех электронных писем, использующих эти домены, я могу собрать уникальный список связанных пользователей.

У пользователей может быть много адресов электронной почты (1 основной + множество дополнительных электронных писем). Пользователи не могут делиться адресами электронной почты (отсюда и поле «VerifiedBy», которое обеспечивает взаимно-однозначную связь между пользователями и электронными письмами).

Моя схема (в настоящее время) выглядит следующим образом:

const emailSchema = new Schema({
    _id: { 
        type: String,
        get: function idReverse(_id) { if(_id) return _id.split("@").reverse().join("@"); },
        set: (str) => { str.trim().toLowerCase().split("@").reverse().join("@") }
    },
    verifiedBy: { type: String, ref: 'User' }
}, options );

Мой вопрос заключается в том, стоит ли обратить вспять доменные части адреса электронной почты в установщике и отменить их в метод получения - как я показал - для того, чтобы базовый индекс MongoDb в _id мог улучшить производительность и упростить работу с видами поиска, которые я описал?

Альтернативы I ' мы уже рассмотрели следующие вопросы:

  • Хранение электронной почты как есть и использование регулярных выражений для выбора пользователей по доменной части (мне кажется, это обходится мне дорого)
  • Хранение доменной части в отдельной поле и индексирование это (чувствует себя дорого, так как было бы два индекса, и дублированное хранилище данных)

1 Ответ

1 голос
/ 06 января 2020

Первые параметры на самом деле должны работать довольно хорошо. Согласно $regex документам :

[...] Дальнейшая оптимизация может произойти, если регулярное выражение является «выражением префикса», что означает, что все потенциальные совпадения начинаются с той же строкой. [...]

Регулярное выражение является «префиксным выражением», если оно начинается с каретки (^) или левого якоря (\ A), за которым следует строка простых символов. [...]


Эксперимент

Давайте проверим, как это работает в коллекции с ~ 800 тыс. Документов, ~ 25% из них имеют электронное письмо. Анализируемый пример запроса: {email: /^gmail/}.

Без индекса:

db.users.find({email: /^gmail/}).explain('executionStats').executionStats
// ...
//    "nReturned" : 2208,
//    "executionTimeMillis" : 250,
//    "totalKeysExamined" : 0,
//    "totalDocsExamined" : 202720,
// ...

С индексом {email: 1}:

db.users.find({email: /^gmail/}).explain('executionStats').executionStats
// ...
//    "nReturned" : 2208,
//    "executionTimeMillis" : 5,
//    "totalKeysExamined" : 2209,
//    "totalDocsExamined" : 2208,
// ...

Как мы видим, это определенно помогает - как с точки зрения времени выполнения, так и проверенных документов (более изученные документы означают, возможно, больше работы ввода-вывода). Давайте посмотрим, как это работает, если мы проигнорируем префикс и будем использовать запрос более непосредственно: {email: /gmail/}.

Без индекса:

db.users.find({email: /gmail/}).explain('executionStats').executionStats
// ...
//    "nReturned" : 2217,
//    "executionTimeMillis" : 327,
//    "totalKeysExamined" : 0,
//    "totalDocsExamined" : 202720,
// ...

С индексом {email: 1}:

db.users.find({email: /gmail/}).explain('executionStats').executionStats
// ...
//    "nReturned" : 2217,
//    "executionTimeMillis" : 210,
//    "totalKeysExamined" : 200616,
//    "totalDocsExamined" : 2217,
// ...

В конце концов, индекс помогает много , особенно при выполнении запроса с префиксом. Похоже, что префиксный запрос достаточно быстрый, чтобы сохранить его в одном поле. Отдельное поле может использовать индекс еще лучше (поиграйте с ним!), Но я думаю, что 5 мс вполне достаточно.

Как всегда, я настоятельно рекомендую вам выполнить тесты на ваши данные и посмотрите, как они работают, так как характеристики c могут повлиять на производительность.

...