复合索引排序顺序
索引会按升序 ( 1
) 或降序 ( -1
)存储对字段的引用。 对于复合索引,排序顺序可以决定索引是否可以支持排序操作。
复合索引支持与索引的排序顺序或索引的反向排序顺序匹配的排序操作。
用例(Use Case)
一款手机游戏有一个显示以下信息的排行榜:
最高游戏分数
获得每个分数的用户
每次得分的日期
该应用程序首先按 score
降序对排行榜进行排序。 然后,与每个score
关联的username
按升序(按字母顺序)排序。
如果索引中的排序顺序与查询中的排序顺序匹配,则复合索引可以提高排行榜的性能。
例子
请考虑一个包含以下文档的 leaderboard
集合:
db.leaderboard.insertMany( [ { "score": 50, "username": "Alex Martin", "date": ISODate("2022-03-01T00:00:00Z") }, { "score": 55, "username": "Laura Garcia", "date": ISODate("2022-03-02T00:00:00Z") }, { "score": 60, "username": "Alex Martin", "date": ISODate("2022-03-03T00:00:00Z") }, { "score": 60, "username": "Riya Patel", "date": ISODate("2022-03-04T00:00:00Z") }, { "score": 50, "username": "Laura Garcia", "date": ISODate("2022-03-05T00:00:00Z") } ] )
该查询返回排行榜结果:
db.leaderboard.find().sort( { score: -1, username: 1 } )
输出:
[ { _id: ObjectId("632235700646eaee87a56a74"), score: 60, username: 'Alex Martin', date: ISODate("2022-03-03T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a75"), score: 60, username: 'Riya Patel', date: ISODate("2022-03-04T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a73"), score: 55, username: 'Laura Garcia', date: ISODate("2022-03-02T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a72"), score: 50, username: 'Alex Martin', date: ISODate("2022-03-01T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a76"), score: 50, username: 'Laura Garcia', date: ISODate("2022-03-05T00:00:00.000Z") } ]
结果先按分数降序进行排序,然后按用户名升序(字母顺序)进行排序。
排行榜的支持索引
以下索引提高了排行榜结果的性能,因为索引的排序顺序与查询中使用的排序顺序匹配:
db.leaderboard.createIndex( { score: -1, username: 1 } )
该复合索引存储:
score
值按降序排列。username
值按升序排列(按字母顺序)。
反向结果
MongoDB 可以在任一方向遍历复合索引。如果应用程序允许用户以相反的顺序查看排行榜,则索引也支持该查询。
以下查询以相反顺序返回排行榜,其中结果首先按升序score
值排序,然后按降序username
值排序(按字母顺序逆序):
db.leaderboard.find().sort( { score: 1, username: -1 } )
输出:
[ { _id: ObjectId("632235700646eaee87a56a76"), score: 50, username: 'Laura Garcia', date: ISODate("2022-03-05T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a72"), score: 50, username: 'Alex Martin', date: ISODate("2022-03-01T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a73"), score: 55, username: 'Laura Garcia', date: ISODate("2022-03-02T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a75"), score: 60, username: 'Riya Patel', date: ISODate("2022-03-04T00:00:00.000Z") }, { _id: ObjectId("632235700646eaee87a56a74"), score: 60, username: 'Alex Martin', date: ISODate("2022-03-03T00:00:00.000Z") } ]
{ score: -1, username: 1 }
索引支持此查询。
不支持的查询
复合索引不支持排序顺序与索引不匹配或与索引相反的查询。因此,{ score:
-1, username: 1 }
索引不支持先按 score
值升序进行排序,然后再按 username
值升序进行排序,例如以下查询:
db.leaderboard.find().sort( { score: 1, username: 1 } )
另外,在使用索引进行排序操作时,排序中指定的字段必须按照它们在索引中的顺序出现。因此,上述索引无法支持该查询:
db.leaderboard.find().sort( { username: 1, score: -1, } )
了解详情
有关排序顺序和索引的更多信息,请参阅使用索引对查询结果进行排序。
有关查询结果排序的更多信息,请参阅
sort()
。