MongoDB复合索引精通指南
本指南深入探讨MongoDB复合索引的细节,这是优化数据库性能的关键技术。我们将涵盖从理解其基本工作原理到分析其有效性和排除常见问题的全部内容。
1. 理解复合索引
在MongoDB中,复合索引是跨越单个文档中多个字段的索引。与仅加速单个字段查询的单字段索引不同,复合索引极大地提高了涉及多个字段的查询速度,从而显著影响应用程序性能。索引中字段的顺序至关重要;MongoDB利用此顺序有效地定位文档。
匹配索引前导字段的查询获益最多。如果查询仅使用前导字段,则该索引将被完全用于过滤和排序。但是,如果查询使用索引之外的字段,MongoDB可能会部分利用索引,可能回退到集合扫描以满足其余条件,从而抵消性能提升。
例如,考虑一个具有字段category
、price
和name
的products
集合。在{ "category": 1, "price": -1 }
上的复合索引优化了按category
过滤然后按price
降序排序的查询。
2. 创建复合索引
使用db.collection.createIndex()
方法可以轻松创建复合索引。参数是一个文档,其中键表示字段名称,值表示排序顺序(1表示升序,-1表示降序)。
// 在category(升序)和price(降序)上创建复合索引
db.products.createIndex( { category: 1, price: -1 } );
// 在多个字段上创建复合索引,排序顺序不同
db.users.createIndex( { firstName: 1, lastName: -1, age: 1 } );
// 添加唯一和稀疏选项
db.products.createIndex( { category: 1, price: -1 }, { unique: true, sparse: true } );
unique: true
强制跨索引字段的唯一性,而sparse: true
仅索引索引字段不为null的文档。
3. 使用复合索引进行查询
如果查询匹配前导字段并且排序顺序一致,MongoDB的查询优化器会自动使用复合索引。例如,以下查询受益于{ "category": 1, "price": -1 }
索引:
db.products.find( { category: "Electronics" } ).sort( { price: -1 } );
此查询按category
(前导索引字段)过滤并按price
(匹配索引的排序顺序)排序。但是,此查询的好处不会那么多:
db.products.find( { price: { $lt: 100 } } ).sort( { category: 1 } );
price
不是前导字段,并且排序顺序与索引不一致。
4. 分析索引使用情况
使用db.collection.find().explain()
分析索引使用情况。这提供了有关查询执行计划的详细信息,包括使用了哪些索引(或未使用)以及执行时间。
db.products.find( { category: "Electronics" } ).sort( { price: -1 } ).explain();
检查“executionStats”部分。如果使用了索引,您将看到索引键的使用情况和检查的文档数量。“COLLSCAN”表示完整集合扫描,效率低于索引使用。
5. 最佳实践和优化
仔细选择索引至关重要。索引过多会减慢写入操作速度,而索引不足会导致查询效率低下。优先考虑常用查询模式,根据需要逐步添加索引。定期监控索引使用情况并根据应用程序需求进行调整。考虑使用MongoDB Compass GUI简化索引管理。
6. 常见问题
- 我应该创建多少个复合索引?最佳数量取决于应用程序的查询模式。需要在避免索引过多和索引不足之间取得平衡。
- 如果我的查询与索引不完全匹配怎么办?MongoDB可能会使用索引的部分内容,但仍可能对不匹配的部分使用集合扫描。
- 我可以创建具有混合升序/降序字段的复合索引吗?可以,顺序对于最佳性能至关重要。
- 如何删除复合索引?使用
db.collection.dropIndex()
,指定索引名称或规范:
// 按名称删除
db.products.dropIndex("category_1_price_-1");
// 按规范删除
db.products.dropIndex( { category: 1, price: -1 } );