我正在使用猫鼬(Mongoose)来保存电子邮件地址的中央集合,并且我还为用户和组织提供了集合。在我的应用程序中,我通过(已验证的)电子邮件域将用户与组织相关联。例如,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 );
我的问题是,是否值得在setter中逆转电子邮件地址的域部分,并在getter中逆转它们(如我所示),以使_id上的基础MongoDb索引可以提高性能并使其更易于处理我描述过的各种查询?
我已经考虑过的替代方法是:
第一个选项实际上应该可以很好地工作。根据$regex
文档:
[...]如果正则表达式是“前缀表达式”,则可能会发生进一步的优化,这意味着所有潜在的匹配都以相同的字符串开头。[...]
如果正则表达式以尖号(^)或左锚(\ A)开头,后跟一串简单符号,则为“前缀表达式”。[...]
让我们检查一下它在包含约80万个文档的集合中如何工作,其中约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,
// ...
如我们所见,它在执行时间和经过检查的文档方面绝对有帮助(更多的经过检查的文档可能意味着更多的IO工作)。让我们来看看它是如何工作的,如果我们将忽略前缀和更直接地使用查询:{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,
// ...
最后,索引有很大帮助,特别是在执行前缀查询时。前缀查询看起来足够快,可以在单个字段中保持原样。一个单独的字段可能会更好地利用索引(使用它!),但是我认为5ms足够了。
与往常一样,我强烈建议您对数据进行测试并查看其性能,因为数据特征可能会影响性能。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句