集群化集合
5.3 版本中的新增功能。
Overview
从MongoDB 5.3开始,您可以使用集群索引创建集合。 使用集群化索引创建的集合称为集群化集合。
收益分析
由于集群化集合存储按集群索引键值排序的文档,因此,与非集群化集合相比,集群化集合具有以下优点:
无需二级索引即可对集群化集合进行更快的查询,例如对集群化索引键进行范围扫描和相等比较的查询。
集群化集合具有较小的存储大小,这提高了查询和批量插入的性能。
集群化集合可免于使用二级 TTL(生存时间)索引。
如果指定了 expireAfterSeconds 字段,则集群化索引也是 TTL 索引。
要用作 TTL 索引,
_id
字段必须是受支持的日期类型。请参阅 TTL 索引。如果使用集群化索引作为 TTL 索引,可以提高文档删除性能并减少集群化集合存储大小。
集群化集合在插入、更新、删除和查询方面实现了性能的进一步提升。
所有集合都有 _id 索引。
非集群化集合将
_id
索引与文档分开存储。这需要对插入、更新和删除进行两次写入,对查询进行两次读取。集群化集合按
_id
值顺序将索引和文档存储在一起。这需要对插入、更新和删除进行两次写入,对查询进行一次读取。
行为
集群化集合可存储按集群化索引键值排序的文档。集群化索引键必须为 { _id: 1 }
。
集合中只能有一个集群索引,因为文档只能按一个顺序存储。只有具有集群索引的集合才能按排序顺序存储数据。
您可以拥有聚簇索引并将二级索引添加到集群化集合中。聚簇索引与二级索引不同:
只有在创建集合时才能创建集群化索引。
集群化索引键与集合一起存储。
collStats
命令返回的集合大小包括集群化索引大小。
从 MongoDB 6.0.7 开始,如果存在可用的集群索引,MongoDB 查询计划器会在查询计划过程中根据二级索引对该集群索引求值。当查询使用集群索引时,MongoDB 会执行有界集合扫描。
在 MongoDB 6.0.7 之前,如果集群化集合上存在二级索引并且二级索引可供查询使用,则查询计划器默认选择二级索引而不是集群索引。在 MongoDB 6.1 及更早版本中,要使用集群索引,您必须提供提示,因为查询优化器不会自动选择集群索引。
重要
向后不兼容的功能
您必须先删除集群化集合,然后才能降级到 5.3 之前的 MongoDB 版本。
限制
集群化集合限制:
集群化索引键必须为
{ _id: 1 }
。不得将非集群化集合转换为集群化集合,反之亦然。相反,您可以:
使用
mongodump
导出集合数据,并使用mongorestore
将数据导入另一个集合。
默认情况下,如果集群化集合上存在二级索引并且查询可以使用二级索引,则选择二级索引而不是集群索引。
必须提供提示才能使用集群索引,因为查询优化器不会自动选择集群索引。
如果存在可用的二级索引,则查询优化器不会自动使用集群索引。
当查询使用聚集索引时,它将执行有界collection扫描。
无法隐藏集群化索引。参见隐藏的索引。
如果集群化集合有二级索引,则此集合具有更大的存储大小。这是因为与非集群化集合的二级索引相比,较大集群化索引键的集群化集合的二级索引可能具有更大的存储大小。
群集群化集合可能不是固定大小集合。
设置自己的聚集索引键值
您可以设置自己的聚簇索引键值。该键:
必须包含一个唯一值。
必须不可变。
应包含依次递增的值。这不是必需的,但有助于提升插入性能。
大小应尽可能小。
集群化索引支持大小最大为 8 MB 的键,但最好使用小得多的集群化索引键。
较大的聚集索引键会导致集群化集合的大小增大,同时二级索引也较大。此情况会削弱集群化集合的性能和存储优势。
与非集群化集合上的二级索引相比,具有大型集群化索引键的集群化集合上的二级索引可能会占用更多空间。
警告
随机生成的键值可能会降低集群化集合的性能。
示例
本部分显示集群化集合示例。
Create
例子
下面的 create
示例添加一个名为 products
的集群化集合:
db.runCommand( { create: "products", clusteredIndex: { "key": { _id: 1 }, "unique": true, "name": "products clustered key" } } )
在此示例中,clusteredIndex 将指定:
"key": { _id: 1 }
,用于按照_id
字段设置集群索引键。"unique": true
,它表示聚集索引键值必须是唯一的。"name": "products clustered key"
,设置集群索引名称。
db.createCollection
例子
下面的 db.createCollection()
示例添加一个名为 stocks
的集群化集合:
db.createCollection( "stocks", { clusteredIndex: { "key": { _id: 1 }, "unique": true, "name": "stocks clustered key" } } )
在此示例中,clusteredIndex 将指定:
"key": { _id: 1 }
,用于按照_id
字段设置集群索引键。"unique": true
,它表示聚集索引键值必须是唯一的。"name": "stocks clustered key"
,设置集群索引名称。
日期聚集索引键示例
下面的 create
示例添加了一个名为 orders
的集群化集合:
db.createCollection( "orders", { clusteredIndex: { "key": { _id: 1 }, "unique": true, "name": "orders clustered key" } } )
在此示例中,clusteredIndex 将指定:
"key": { _id: 1 }
,用于按照_id
字段设置集群索引键。"unique": true
,它表示聚集索引键值必须是唯一的。"name": "orders clustered key"
,设置集群索引名称。
以下示例将文档添加到 orders
集合:
db.orders.insertMany( [ { _id: ISODate( "2022-03-18T12:45:20Z" ), "quantity": 50, "totalOrderPrice": 500 }, { _id: ISODate( "2022-03-18T12:47:00Z" ), "quantity": 5, "totalOrderPrice": 50 }, { _id: ISODate( "2022-03-18T12:50:00Z" ), "quantity": 1, "totalOrderPrice": 10 } ] )
_id
clusteredIndex 密钥会存储订单日期。
如果在范围查询中使用 _id
字段,性能将得到提升。例如,以下查询使用 _id
和 $gt
以返回日期晚于所提供日期的订单:
db.orders.find( { _id: { $gt: ISODate( "2022-03-18T12:47:00.000Z" ) } } )
示例输出:
[ { _id: ISODate( "2022-03-18T12:50:00.000Z" ), quantity: 1, totalOrderPrice: 10 } ]
确定集合是否为集群化集合
使用 listCollections
命令可确定集合是否集群化:
db.runCommand( { listCollections: 1 } )
对于集群化集合,您将在输出中看到 clusteredIndex 的详细信息。例如,以下输出显示了 orders
集群化集合的详细信息:
... name: 'orders', type: 'collection', options: { clusteredIndex: { v: 2, key: { _id: 1 }, name: 'orders clustered key', unique: true } }, ...
v
是索引版本。