面试题答案
一键面试分析思路
- 查询分析:
- 使用
explain
命令分析查询计划,了解查询如何使用索引。查看winningPlan
中的stage
,比如是COLLSCAN
(全表扫描)还是IXSCAN
(索引扫描)。如果是全表扫描,分析是否索引选择不当或数据分布导致索引无法有效利用。 - 确定查询的频率和重要性。对于频繁且对业务关键的查询,应优先优化;对于偶尔执行的查询,优化优先级可降低。
- 使用
- 索引分析:
- 检查索引的冗余性。多个索引可能覆盖相同或部分相同的字段,导致插入、更新操作性能下降。例如,如果有索引
{a: 1, b: 1}
和{a: 1}
,在某些情况下,{a: 1}
可能是冗余的。 - 查看索引的选择性。选择性高的索引(即索引字段值的唯一性高)对查询性能提升更有效。可以通过计算
distinct
值的数量与文档总数的比例来评估索引字段的选择性。 - 考虑复合索引的顺序。复合索引中字段的顺序很关键,应将选择性高、过滤性强的字段放在前面。例如,对于查询
find({a: value1, b: value2})
,如果a
的选择性更高,复合索引应是{a: 1, b: 1}
。
- 检查索引的冗余性。多个索引可能覆盖相同或部分相同的字段,导致插入、更新操作性能下降。例如,如果有索引
- 数据分布分析:
- 了解数据的分布情况,比如是否存在数据倾斜。如果某个索引字段的大部分值集中在少数几个值上,索引的效果会大打折扣。例如,一个状态字段,90% 的文档状态为“已完成”,那么基于这个状态字段的索引在查询非“已完成”状态文档时可能效果不佳。
优化措施
- 索引优化:
- 重建索引:使用
reIndex
命令重建索引,可能会修复索引结构问题,提高索引性能。例如,在索引碎片化严重时,重建索引可以重新组织索引数据,提高查询效率。 - 调整索引:根据分析结果,删除冗余索引,调整复合索引字段顺序或创建新的更合适的索引。比如,如果发现某个复合索引中字段顺序不合理,可删除原索引并创建新的顺序正确的复合索引。
- 重建索引:使用
- 查询优化:
- 改写查询:尝试以不同方式表达查询,使其能更好地利用现有索引。例如,避免在查询条件中对索引字段使用函数,如
find({$where: "function() { return this.field.toUpperCase() === 'VALUE'}"})
应改写为find({field: "VALUE".toUpperCase()})
。 - 使用聚合框架:对于复杂查询,聚合框架有时能更有效地利用索引。例如,使用
$match
阶段进行过滤,$match
阶段如果条件合适,可以利用索引进行快速筛选。
- 改写查询:尝试以不同方式表达查询,使其能更好地利用现有索引。例如,避免在查询条件中对索引字段使用函数,如
- 数据优化:
- 数据分片:如果数据存在倾斜,可考虑进行数据分片,将数据均匀分布到多个分片上,提高查询性能。例如,根据某个字段(如日期)进行范围分片,避免数据集中在少数几个分片上。
- 数据归档:对于历史数据,进行归档处理,将不常用的数据移动到其他存储(如冷存储),减少主数据库的数据量,从而提高查询性能。