独特的索引如何真正起作用并避免碰撞?

Cor*_*ped 6 indexing duplicates unique-constraint mongodb

假设我有一个集合,我在字段上创建一个唯一索引:

db.users.createIndex({username: 1}, {unique:true})
Run Code Online (Sandbox Code Playgroud)

如果具有相同用户名的两个文档同时插入集合中会发生什么?
数据库如何防止冲突?我的意思是哪一个插入,哪个导致错误?
假设插入实际上是SIMULTANEOUS,数据库无法知道正在插入两个重复项,对吧?
那么,究竟发生了什么?

Mar*_*erg 6

写入不能同时应用于数据集.当写入发送到MongoDB实例时,无论是分片还是独立服务器,都会发生这种情况

  1. 请求集合宽写锁(驻留在RAM中)
  2. 授予锁定后,将根据唯一索引(通常驻留在RAM中)检查要写入的结果数据(无论是更新,upsert还是新文档)
  3. 如果没有冲突,则将数据应用于RAM中的数据集
  4. 锁被释放.只有现在其他写入才能开始对内存中的数据进行更改.
  5. 使用默认写入问题时,查询现在返回
  6. commitIntervalMs之后,数据被写入日志
  7. 只有在syncInterval秒后(默认为60),日志才会应用于数据文件

话虽这么说,我们可以看看实际值.对于单个服务器来说,100万次写入/秒似乎有点多(仅仅因为大容量存储无法处理它),因此我们假设一个带有10个分片的分片群集,其中一个分片键可以或多或少均匀地分配写入.如上所述,所有操作都应用于RAM中.使用今天的硬件,可以处理大约35亿条指令/秒,或者每纳秒3.5条指令.让我们假设获得和释放一个锁,每个指令需要35个指令或10纳秒.因此,对于我们的每次100k写入,锁定和解锁将花费20纳秒,总共1/500秒.

对于MongoDB需要做的其他事情,这将留下499/500秒或998000000纳秒,这意味着高达34.93 亿条指令.

防止并发写入的锁远远不是写操作的限制因素.将更改同步到日志和数据文件通常是限制因素,然后减少RAM以将索引和工作集保存在RAM中.

  • @PeteGarafano这是一个社区wiki的答案,你的见解将是一个很好的补充(我不会用它研磨代表,因为没有人获得维基答案的代表) (2认同)