为什么需要 compact
remove 与 drop 的区别
MongoDB 里删除一个集合里所有文档,有两种方式
· db.collection.remove({}, {multi: true}),逐个文档从 btree 里删除,最后所有文档被删除,但文件物理空间不会被回收
· db.collection.drop() 删除集合的物理文件,空间立即被回收
总的来说,remove 会产生逻辑的空闲空间,这些空间能立即用于写入新数据,但文件占用的总物理空间不会立即回收;通常只要持续在写入数据,有物理空间碎片问题并不大,不需要去 compact 集合,有的场景,remove 了大量的数据后,后续的写入可能并不多,这时如果想回收空间,就需要显式的调用 compact。
compact 命令对读写的影响
compact 一个集合,会加集合所在DB的互斥写锁,会导致该DB上所有的读写请求都阻塞;因为 compact 执行的时间可能很长,跟集合的数据量相关,所以强烈建议在业务低峰期执行,避免影响业务。
compact 具体做了什么?
Compact 动作最终由存储引擎 WiredTiger 完成,WiredTiger 在执行 compact 时,会不断将集合文件后面的数据往前面空闲的空间写,然后逐步 truancate 文件回收物理空间。每一轮 compact 前,WT 都会先检查是否符合 comapact 条件
1. 前面80%的空间里,是否有20%的空闲空间,用于写入文件后面20%的数据,或者
2. 前面90%的空间里,是否有10%的空闲空间,用于写入文件后面10%的数据
如果上面都不满足,说明执行compact肯定无法回收10%的物理空间,此时 compact 就回退出。所以有时候遇到对一个大集合进行 compact,compact立马就返回ok,集合的物理空间也没有变化,就是因为 WiredTiger 认为这个集合没有 compact 的必要。
如何预估compact能回收多少空间?
The amount of empty space available for reuse by WiredTiger is reflected in the output of db.collection.stats() under the heading wiredTiger.block-manager.file bytes available for reuse.
db.coll.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
--------查看集合需回收的磁盘碎片空间。
use trff
db.photo_is.chunks.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
db.photo_cr.chunks.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
返回结果大概13T
NumberLong("13453070893056")
----查询具体分片compact能回收多少空间
db.getCollection("photo_is.chunks").stats().shards["shard3"].wiredTiger["block-manager"]["file bytes available for reuse"]
--看看,shards上没有分片的数据有多少
use trff
db.getCollection("photo_is.chunks").stats().shards.shard3.freeStorageSize
db.getCollection("photo_is.chunks").stats().shards.shard2.dataSize
db.getCollection("photo_is.chunks").stats().shards.shard2.freeStorageSize
db.getCollection("photo_is.chunks").stats().shards.shard5.freeStorageSize
--看看,shards上没有分片的数据有多少
db.getCollection("photo_cr.chunks").stats.shards.shard3.freeStorageSize
参数说明:<collection_name>为集合名称。
说明 您可以通过show tables命令查询现有的集合。
--查看gridfs 块文件分布
db.photo_is.chunks.getshardDistribution()
db.photo_cr.chunks.getshardDistribution()
----回收Shard组件中主节点(Primary节点)的磁盘碎片。
db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>",force:true}})
db.runCommand({runCommandOnShard:"shard3","command":{compact:"photo_is.chunks",force:true}})
参数说明:
<Shard ID>:Shard组件的ID。 sh.status() 查看
<collection_name>:集合名称。
说明 您可以通过show tables命令查询现有的集合。
force:可选项,取值固定为true。
如果您的分片集群实例版本为4.2及以下版本,该参数为必填项。
示例:
db.runCommand({runCommandOnShard:"shard01","command":{compact:"sharded_collection",force:true}})
回收Shard组件中从节点(Secondary节点)的磁盘碎片。
db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>"},$queryOptions: {$readPreference: {mode: 'secondary'}}})
db.runCommand({runCommandOnShard:"shard2","command":{compact:"photo_is.chunks"},$queryOptions: {$readPreference: {mode: 'secondary'}}})
参数说明:
<Shard ID>:Shard组件的ID。 sh.status() 查看
<collection_name>:集合名称。
说明 您可以通过show tables命令查询现有的集合。
force:可选项,取值固定为true。
示例:
db.runCommand({runCommandOnShard:"shard2","command":{compact:"photo_cr.chunks"},$queryOptions: {$readPreference: {mode: 'secondary'}}})
查看回收磁盘碎片后数据库占用的磁盘空间。
db.stats()
执行 compact
执行前请确保你已经读懂了上面的内容,知道compact命令的原理、影响
// compact somedb.somecollection
use somedb
db.runCommnd({compact: "somecollection"})
// compact oplog,在副本集primary上执行需要加 force 选项
use local
db.runCommnd({compact: "somecollection", force: true})_x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010__x0010_
参考资料
sh.shardCollection()
定义
sh.shardCollection(命名空间,键,唯一,选项)
使用s key作为分片键对集合进行分片。sh.shardCollection()接受以下参数:
参数 | 类型 | 描述 |
namespace | 串 | 以形式分片的集合 的名称空间<database>.<collection>。 |
key | 文献 | 索引规范文件用作分片 键。分片键确定MongoDB如何在分片之间分配文档。 索引规范文档的密钥是用作分片密钥的字段。该文档的值必须是以下值之一: o 1用于基于范围的分片 o "hashed"指定 哈希分片键。 除非集合为空,否则索引必须在shardCollection命令之前存在 。如果集合为空,那么如果尚不存在可支持分片键的索引,则MongoDB会在分片集合之前创建索引。 另请参阅分片索引 |
unique | 布尔值 | 可选的。当为时true,该unique选项可确保基础索引强制执行唯一约束。哈希分片键不支持唯一约束。默认为false。如果指定 options文件,unique则为required。unique在为options文档指定值时省略的值可能会导致分片的集合不正确。 |
options | 文献 | 可选的。包含可选字段(包括numInitialChunks和)的文档 collation。 |
该options参数支持以下选项:
参数 | 类型 | 描述 |
numInitialChunks | 整数 | 可选的。指定使用散列的分片键分片空集合时最初要创建的块数。然后,MongoDB将在整个集群中创建和平衡块。本必须小于每碎片。numInitialChunks8192 在版本4.0.3中更改:如果为空集合定义了区域和区域范围,则该选项无效。请参阅区域分片和初始块分布。 在版本3.4中进行了更改:如果集合不为空或分片键不是哈希键,则该操作将返回错误。 |
collation | 文献 | 可选的。如果指定为的集合shardCollection 具有默认排序规则,则必须包含带有的排序规则文档 ,否则命令将失败。其字段支持分片键模式的至少一个索引必须具有简单的排序规则。{ locale : "simple" }shardCollection |
注意事项
在调用之后,MongoDB没有提供任何方法来停用集合的分片shardCollection。此外,在之后 shardCollection,您无法更改分片键的选择。但是,从MongoDB 4.2开始,您可以更新文档的分片键值(除非分片键字段是不可变 _id字段)。有关详细信息,请参见更改文档的分片键值。
分片键
选择最佳的分片密钥以有效地在各个分片之间分配负载需要进行一些计划。回顾碎片钥匙 关于所选择片键和限制。
哈希分片键
哈希分片键使用单个字段的哈希索引作为分片键。
使用表格指定散列的分片键。哈希分片键可能不是复合索引。{field: "hashed"}
注意
如果在创建哈希分片键集合时正在进行块迁移,则初始块分布可能会不均衡,直到平衡器自动平衡该集合为止。
也可以看看
区域分片和初始块分布
在版本4.0.3中更改。
如果已经为收集定义了区域和区域范围,则分片收集操作(即shardCollection 命令和sh.shardCollection()帮助程序)可以为空或不存在的收集执行初始块创建和分配。初始块分配允许更快地设置分区分片。在初始分配之后,平衡器将按常规管理前进的块分配。
numInitialChunks如果为空集合定义了区域和区域范围,则该选项无效。
有关示例,请参见为空集合或不存在的集合预定义区域和区域范围。
也可以看看
唯一
如果指定:unique: true
o 如果集合为空,sh.shardCollection()则在分片键上创建唯一索引(如果该索引尚不存在)。
o 如果集合不为空,则必须在使用之前先创建索引sh.shardCollection()。
尽管您可以拥有一个唯一的复合索引,其中分片键是一个前缀,但如果使用unique parameter,则集合必须在分片键上具有一个唯一索引。
另请参见分片集合和唯一索引
整理
在版本3.4中更改。
如果集合具有默认排序规则,则该sh.shardCollection命令必须包含collation带有值的参数。对于具有默认排序规则的非空集合,您必须至少具有一个简单排序规则的索引,该索引的字段支持分片键模式。{ locale: "simple" }
您无需collation为没有排序规则的集合指定选项。如果确实为没有排序规则的集合指定排序规则选项,则它将无效。
写关注
mongos使用"majority"了 写关注的的 shardCollection命令及其助手 sh.shardCollection()。
例子
简单的用法
给定在名为people的数据库中命名records的集合,以下命令将按zipcode字段对该集合进行分片 :
sh.shardCollection("records.people", { zipcode: 1 } )
与选项一起使用
该phonebook数据库具有收藏contacts与没有默认的排序规则。以下示例用于 sh.shardCollection()将phonebook.contactswith分片:
o 一个哈希片键的 last_name字段,
o 5 初始块,以及
o 一个整理的simple。
sh.shardCollection(
"phonebook.contacts",
{ last_name: "hashed" },
false,
{
numInitialChunks: 5,
collation: { locale: "simple" }
})
也可以看看
重写集合中的所有数据和索引并对其进行碎片整理。在 WiredTiger数据库上,此命令将释放不需要的磁盘空间到操作系统。
compact 具有以下形式:
{ compact: <collection name> }
compact 包含以下字段:
从MongoDB 4.2开始
MongoDB中删除MMAPv1存储引擎和MMAPv1特定选项paddingFactor,paddingBytes,preservePadding 的compact。
领域 | 类型 | 描述 |
compact | 串 | 集合的名称。 |
force | 布尔值 | 可选的。如果为true,则compact可以在副本集中的主数据库上运行 。如果, 当在主运行返回一个错误,因为该命令禁止所有其他操作。falsecompact compact 仅针对正在压缩的数据库阻止操作。 |
警告
在执行服务器维护(如compact操作)之前,请始终进行最新备份。
compact所需特权
对于执行身份验证的集群,您必须使用compact对目标集合进行特权操作的用户身份进行身份验证。该dbAdmin角色提供了compact针对非系统集合运行所需的特权。
对于系统集合,请创建一个自定义角色,以授予compact对该系统集合执行的操作。然后,您可以将该角色授予新用户或现有用户,并以该用户身份进行身份验证以执行compact命令。例如,以下操作创建一个自定义角色,该角色将compact针对指定的数据库和集合授予操作:
use admindb.createRole(
{
role: "myCustomCompactRole",
privileges: [
{
resource: { "db" : "<database>" , "collection" : "<collection>" },
actions: [ "compact" ]
}
],
roles: []
})
有关配置resource文档的更多信息,请参见 资源文档。
要将dbAdmin或自定义角色添加到现有用户,请使用db.grantRolesToUser或db.updateUser()。以下操作将自定义compact角色 授予数据库myCompactUser上的admin:
use admindb.grantRolesToUser("myCompactUser", [ "dbAdmin" | "myCustomCompactRole" ] )
要将dbAdmin或自定义角色添加到新用户,请在创建用户时roles在db.createUser()方法数组中 指定角色。
use admindb.createUser(
{
user: "myCompactUser",
pwd: "myCompactUserPassword",
roles: [
{ role: "dbAdmin", db: "<database>" } | "myCustomCompactRole"
]
})
行为
阻断
compact仅阻止当前正在运行的数据库的操作。仅compact在计划的维护期内使用。
您可以通过查看mongod日志文件或db.currentOp() 在另一个Shell实例中运行来查看中间进度 。
操作终止
如果使用该db.killOp()方法终止操作或在compact操作完成之前重新启动服务器 ,请注意以下几点:
o 如果启用了日记功能,则无论compact操作状态如何,数据均保持有效和可用。您可能必须手动重建索引。
o 如果未启用日记功能,并且操作期间mongod或 compact终止,则无法保证数据处于有效状态。
o 无论哪种情况,集合中许多现有的可用空间都可能变得不可重用。在这种情况下,您应该重新运行压缩以完成操作,以恢复对该可用空间的使用。
磁盘空间
要查看集合的存储空间如何变化collStats,请在压缩之前和之后运行 命令。
在WiredTiger上,compact尝试减少集合中数据和索引所需的存储空间,从而将不必要的磁盘空间释放给操作系统。此操作的有效性取决于工作负载,并且无法恢复任何磁盘空间。如果您已从集合中删除了大量数据并且不打算替换它,则此命令很有用。
compact 可能需要更多磁盘空间才能在WiredTiger数据库上运行。
副本集
o 分别压缩每个成员。
o 理想情况下compact在辅助服务器上运行。force:true有关压缩主数据库的信息,请参见上面的选项 。
o 在辅助服务器上,该compact命令会强制辅助服务器进入RECOVERING状态。向处于该RECOVERING状态的实例发出的读取操作将失败。这样可以防止客户端在操作过程中阅读。操作完成后,辅助服务器返回SECONDARY状态。
o 有关副本集成员状态的更多信息,请参见副本集成员状态。
请参阅对副本集成员执行维护以获取示例副本集维护过程,以在维护操作期间最大程度地提高可用性。
分片群集
compact仅适用于mongod实例。在分片环境中,compact作为维护操作,分别在每个分片上运行。
封顶集合
在WiredTiger上,该compact 命令将尝试压缩集合。




