面试题答案
一键面试原因分析
- 片键选择问题:片键为
user_id
,而查询是基于user_name
。MongoDB的分片集群是根据片键来分布数据的,按user_name
查询时,无法利用片键的分布优势,可能需要在所有分片上进行全量扫描来获取数据,导致性能较差。 - 缺少索引:如果没有为
user_name
字段建立索引,在执行查询时,数据库需要全表扫描集合中的每一个文档来匹配user_name
,这在数据量较大时性能损耗严重。
优化策略
- 建立索引:
- 为
user_name
字段创建单字段索引。例如在MongoDB shell中使用db.collection.createIndex( { user_name: 1 } )
,其中1
表示升序索引,也可根据实际需求改为-1
降序索引。通过索引,数据库可以快速定位到满足user_name
条件的文档,大大提高查询效率。
- 为
- 调整片键(需谨慎):
- 如果业务允许,并且数据分布情况合适,可以考虑将片键调整为
user_name
。这样数据将按照user_name
进行分片,按user_name
查询时,能直接定位到相应的分片,减少不必要的跨分片查询。但此操作需要谨慎,因为调整片键可能涉及数据的重新分布,在大数据量情况下可能导致集群负载升高甚至影响业务正常运行。
- 如果业务允许,并且数据分布情况合适,可以考虑将片键调整为
- 二级索引与覆盖索引:
- 如果查询不仅返回
user_name
相关数据,还涉及其他字段,可以创建覆盖索引。例如db.collection.createIndex( { user_name: 1, other_field1: 1, other_field2: 1 } )
,这样查询所需的数据都可以从索引中获取,避免回表操作,进一步提升查询性能。
- 如果查询不仅返回