MongoDB分片,唯一索引与upsert
前言
分片,唯一索引和upsert,表面上看似没有直接联系的几个东西,到底存在怎样的瓜葛呢?
分片
为了保持水平扩展的有效性,分片功能必须保证各个片之间没有直接关联,不需要与其他分片交互就可以独立做出决策。如果不能满足这一点,随着分片数量不断增加,需要交互的分片越来越多,势必会越来越慢,那么就违背了分片的初衷了。比如JOIN就是一种典型的破坏分片独立性的功能。在一个n个分片的集群中,为了得到笛卡尔积,每个分片必须与其他n-1个分片交互来得到结果。虽然不见得是线性的延迟增长(因为n-1个请求可以并行),但是可想而知对资源将是极大的消耗,并且随着分片数量的增长影响会越来越显著,最终会到达“增加一个分片可能对性能完全没有帮助”,或者“增加一个分片反而降低性能”的地步。
唯一索引
唯一索引是另外一个显著破坏分片独立性的特性。前面对JOIN的分析完全适用于唯一索引,并且更糟的情况是唯一索引还有有更进一步的恶劣影响,那就是在写入数据的时候必须占用一个跨分片的全局锁,否则无法保证其唯一性,可想而知对性能有怎样的影响。这也是MongoDB为什么不打算去实现全局唯一索引的原因。
有一种特殊情况却可以改变这种不利状况,那就是唯一索引的键正好是片键的时候。片键一旦确定,文档该去哪个分片就确定了,那么只要保证该键在这一个片上唯一就可以了,不再需要去与其他分片协商。
upsert
从语义上讲,我们使用upsert一般是希望一个键只出现一次的(不然每次insert就好了)。这一点恰恰是唯一索引要干的事情,而唯一索引又存在上面的所说的问题,因此唯一有意义的情况则是upsert使用的条件正好是片键,且片键唯一。
满足了上面这些条件就高枕无忧了吗?并不是。在决定一个键是不是存在,到执行update/insert之间,是存在空隙的。即,检测和执行并不在一个原子操作中,也不可能在一个原子操作中,否则将是一个很大粒度的锁。再说,MongoDB对文档级别并没有真正通过加锁来控制,而是通过“乐观并发控制”(optimistic concurrency control)来进行的。
因此,出于效率考虑,不是原子操作是正确的选择,而解决这个问题也不是特别麻烦的事情,实际上只需要在遇到duplicate key异常的时候重试该操作就可以了,因为重试的时候理论上就应该变成update而不再是insert,自然避免了问题。或者,在4.2中直接实现了这类错误的自动重试(SERVER-37124)。
参考资料
- Unique Indexes: https://docs.mongochina.com/core/index-unique.html
- Retry full upsert path when duplicate key exception matches exact query predicate: https://jira.mongodb.org/browse/SERVER-37124
MongoDB分片,唯一索引与upsert的更多相关文章
- TokuMX唯一索引不支持dropDups选项
TokuMX v1.5.0的唯一索引(unique index)不支持dropDups选项, 如果源数据包含相同目标key的文档,将无法建立唯一索引. 问题场景: 从MongoDB到TokuMX的数据 ...
- MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划
这篇文章主要介绍了MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划的相关资料,需要的朋友可以参考下 一.索引 MongoDB 提供了多样性的索引支持,索引信息被保存 ...
- MongoDB 创建基础索引、组合索引、唯一索引以及优化
一.索引 MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes 中,且默认总是为_id创建索引,它的索引使用基本和MySQL 等关系型数据库一样.其实可以这样说说,索引 ...
- MongoDB小结25 - 复合唯一索引
只要满足索引的其中之一不同即可 db.blog.ensureIndex({"username":1,"blogname":1}) 作者和作品名其中之一不同即可创 ...
- MongoDB的复合唯一索引
一 创建 JavaScript Shell db.room.ensureIndex({'floor':1,'num':1}) Spring Data @Data // lombok @Document ...
- mongodb 索引,全文索引与唯一索引
唯一索引创建: db.createIndex({name: 1}, {unique: true})
- MongoDB(课时22 唯一索引)
3.6.1 唯一索引 唯一索引的主要目的是用在某一个字段上,使该字段的内容不重复. 范例:创建唯一索引 db.students.ensureIndex({"name" : 1}, ...
- 4.非关系型数据库(Nosql)之mongodb:普通索引,唯一索引
一:普通索引 1创建一个新的数据库 > use toto; switched to db toto > show dbs; admin (empty) local 0.078GB & ...
- MongoDB 分片管理(不定时更新)
背景: 通过上一篇的 MongoDB 分片的原理.搭建.应用 大致了解了MongoDB分片的安装和一些基本的使用情况,现在来说明下如何管理和优化MongoDB分片的使用. 知识点: 1) 分片的配置和 ...
随机推荐
- [RN] React Native 获取地理位置
React Native 获取地理位置 实现原理: 1.用 navigator.geolocation.getCurrentPosition 获取到坐标信息 2.调用 高德地图 接口,解析位置数据 ...
- selenium--浏览器窗口截图
前戏 在进行web自动化的时候,只有一个报错信息是不行的,往往需要截图来帮助我们来快速的定位问题,试想一下,我们在一个弹框里添加一些数据,点击保存后,然后在操作元素,这时selenium报错,说找不到 ...
- Linux下进程间通信方式——共享内存
1.什么是共享内存? 共享内存就是允许两个或多个进程共享一定的存储区.就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针.当一个进程改变了这块地址中的内容的时候,其它进程都会察 ...
- 剑指offer15 二进制中1的个数
题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如,把9表示成二进制是1001,有2位是1.因此,如果输入9则函数输出2. int Number(int n) { ; while ...
- 《深度学习框架PyTorch:入门与实践》读书笔记
https://github.com/chenyuntc/pytorch-book Chapter2 :PyTorch快速入门 + Chapter3: Tensor和Autograd + Chapte ...
- ES6基础-ES6的扩展
进行对字符串扩展,正则扩展,数值扩展,函数扩展,对象扩展,数组扩展. 开发环境准备: 编辑器(VS Code, Atom,Sublime)或者IDE(Webstorm) 浏览器最新的Chrome 字符 ...
- C语言实现聊天室软件
/* common.h */ /*服务器端口信息*/ #define PORTLINK ".charport" /*缓存限制*/ #define MAXNAMELEN 256 #d ...
- java_home not found in your enviroment 问题解决方法
java_home not found in your enviroment 错误原因有一下几点 1. JAVA_HOME系统环境没配置, JAVA_HOME环境变量配置方法: <1> 右 ...
- Linux常用基础(三)
1.gcc编译器 (1)简介 前期的GCC是GNU C Compiler,仅仅用于C语言的编译,经过多年的发展,现在的GCC为GNU Compiler Collection,并且目前支持多种编程语言的 ...
- centos7下vs code编辑器字体与windows版本同步设置-安装中文字体,美化vscode
"editor.fontFamily": "Consolas, 'Courier New', monospace" 从window10系统中复制出以上字体,到C ...