唯一索引如何真正起作用并避免冲突?
How do unique indexes really work and avoid collisions?
假设我有一个集合,我在其中创建了一个字段的唯一索引:
db.users.createIndex({username: 1}, {unique:true})
如果将两个具有相同用户名的文档同时插入到集合中会怎样?
数据库是如何防止碰撞的?我的意思是哪个被插入,哪个导致错误?
假设插入确实是同步的,那么数据库无法知道插入了两个重复项,对吗?
那么,到底发生了什么?
写入不能同时应用于数据集。当写入发送到 MongoDB 实例时,无论是分片还是独立服务器,都会发生以下情况
- 请求一个集合范围的写锁(驻留在 RAM 中)
- 授予锁定后,将根据唯一索引(通常驻留在 RAM 中)检查要写入的结果数据(无论是更新、更新插入还是新文档)
- 如果没有碰撞,则将数据应用到RAM中的数据集
- 锁被释放。只有现在其他写入才能开始对内存中的数据执行更改。
- 使用默认写入关注,查询 returns 现在
- 在commitIntervalMs之后数据被写入日志
- 仅在 syncInterval 秒(默认为 60 秒)后,日志才会应用于数据文件
话虽如此,我们还是可以看看实际值。每秒 100 万次写入对于单个服务器来说似乎有点多(仅仅是因为海量存储无法处理它),因此我们假设一个具有 10 个分片的分片集群,以及一个或多或少均匀分布写入的分片键。正如我们在上面看到的,所有操作都在 RAM 中应用。使用今天的硬件,可以处理大约 35 亿 instructions/s,或每纳秒 3.5 条指令。假设获取和释放锁各需要 35 条指令或 10 纳秒。因此,我们每次 100k 写入的锁定和解锁将花费 20 纳秒,总共是 1/500 秒。
这将为 MongoDB 需要做的其他事情留下 499/500 秒或 998000000 纳秒,这转化为高达 3.493 十亿 指令。
防止并发写的锁远不是写操作的限制因素。将更改同步到日志和数据文件通常是限制因素,其次是减少 RAM 以将索引和工作集保留在 RAM 中。
假设我有一个集合,我在其中创建了一个字段的唯一索引:
db.users.createIndex({username: 1}, {unique:true})
如果将两个具有相同用户名的文档同时插入到集合中会怎样?
数据库是如何防止碰撞的?我的意思是哪个被插入,哪个导致错误?
假设插入确实是同步的,那么数据库无法知道插入了两个重复项,对吗?
那么,到底发生了什么?
写入不能同时应用于数据集。当写入发送到 MongoDB 实例时,无论是分片还是独立服务器,都会发生以下情况
- 请求一个集合范围的写锁(驻留在 RAM 中)
- 授予锁定后,将根据唯一索引(通常驻留在 RAM 中)检查要写入的结果数据(无论是更新、更新插入还是新文档)
- 如果没有碰撞,则将数据应用到RAM中的数据集
- 锁被释放。只有现在其他写入才能开始对内存中的数据执行更改。
- 使用默认写入关注,查询 returns 现在
- 在commitIntervalMs之后数据被写入日志
- 仅在 syncInterval 秒(默认为 60 秒)后,日志才会应用于数据文件
话虽如此,我们还是可以看看实际值。每秒 100 万次写入对于单个服务器来说似乎有点多(仅仅是因为海量存储无法处理它),因此我们假设一个具有 10 个分片的分片集群,以及一个或多或少均匀分布写入的分片键。正如我们在上面看到的,所有操作都在 RAM 中应用。使用今天的硬件,可以处理大约 35 亿 instructions/s,或每纳秒 3.5 条指令。假设获取和释放锁各需要 35 条指令或 10 纳秒。因此,我们每次 100k 写入的锁定和解锁将花费 20 纳秒,总共是 1/500 秒。
这将为 MongoDB 需要做的其他事情留下 499/500 秒或 998000000 纳秒,这转化为高达 3.493 十亿 指令。
防止并发写的锁远不是写操作的限制因素。将更改同步到日志和数据文件通常是限制因素,其次是减少 RAM 以将索引和工作集保留在 RAM 中。