面试题答案
一键面试第一个查询需求:查询点赞数大于100且评论数大于50的最近一周内发布的帖子
- 索引设计思路:
- 这个查询涉及点赞数、评论数和发布时间三个字段。为了达到最优性能,我们应该创建一个复合索引,将查询条件中的字段按查询条件的选择性从高到低排列。一般来说,点赞数和评论数的选择性相对较高,而时间范围(最近一周)相对较宽泛。所以索引顺序为点赞数、评论数、发布时间。
- 可能遇到的问题:
- 索引覆盖:如果查询返回的字段都包含在索引中,那么可以使用索引覆盖,直接从索引中获取数据,而不需要回表操作,从而提高查询性能。例如,如果只查询帖子ID、点赞数、评论数和发布时间,这个索引就可以实现索引覆盖。
- 索引冲突:如果数据库中已经存在其他索引,新创建的索引字段顺序与已有索引冲突,可能会导致索引维护成本增加。例如已有索引是(发布时间,点赞数),而新创建的索引为(点赞数,评论数,发布时间),虽然字段有重合,但顺序不同,可能会在某些操作(如插入、更新)时增加额外的索引更新开销。
- 索引创建语句:
db.posts.createIndex({likes: 1, comments: 1, publishTime: 1});
这里likes
表示点赞数,comments
表示评论数,publishTime
表示发布时间,1表示升序排列(如果是 -1 则表示降序排列)。
第二个查询需求:查询某个用户发布的点赞数排名前10的帖子
- 索引设计思路:
- 此查询涉及用户ID和点赞数两个字段。创建一个复合索引,将用户ID放在前面,因为要先定位到特定用户,然后再根据点赞数进行排序。所以索引为(用户ID,点赞数)。
- 可能遇到的问题:
- 索引覆盖:如果查询返回的字段都包含在索引中,例如只查询帖子ID、用户ID和点赞数,那么可以利用索引覆盖,避免回表操作,提升查询效率。
- 索引冲突:如果已有索引包含用户ID或者点赞数且顺序不同,可能会产生索引冲突。比如已有索引是(点赞数,用户ID),新创建(用户ID,点赞数),在数据操作时可能会增加索引维护成本。
- 索引创建语句:
db.posts.createIndex({userId: 1, likes: -1});
这里userId
表示用户ID,likes
表示点赞数,-1表示点赞数以降序排列,这样可以直接获取点赞数排名前10的帖子。