access建立两个字段唯一索引_关于MongoDB唯一索引(Unique)的那些事
写在前面
关于什么是索引以及唯一索引这里就不做说明了,不清楚的可以自行谷歌或者百度。是什么引起我写这篇文章呢,这来自于之前项目中的一个问题。
我们用的是MongoDB数据存储用户信息,用户表中曾经用户注册是通过手机号注册的,所以很理所当然的给手机号加上了唯一索引(Unique),这是没有什么毛病。
后期,我们需求改了。你也可以想到变成了既可以手机号注册又可以邮箱注册,这个时候由于手机号加了Unique索引,事实上这时候是会出现问题的。
func init() { phoneIndex := mgo.Index{ Key: []string{"phone"}, Unique: true, } col := db.Collection(&User{}) col.EnsureIndex(phoneIndex)}
当然这问题其实也容易想到,当用户通过邮箱注册此时手机号填空的时候,第一次没什么问题,下个用户再以这种方式注册的时候便会提示建立在phone上的索引值重复,很正常嘛,因为插入了两个空值,注意这里是空字符串,而不是null。
于是我们尝试修改,由于MongoDB是文档型灵活的数据库,少插多插一两个字段不受影响,所以我们尝试修改User实体Phone字段的入口,当phone是空字符串的时候,不让插入此字段。
于是,我们便在phone字段中加入了omitempty标签(我们微服务用Go语言写的)。下面展示User一部分内容:
type User struct { Email string `bson:"email"` Salt string `bson:"salt"` Phone string `bson:"phone,omitempty"` IDCard string `bson:"idcard"` RealName string `bson:"realname"` AuthStatus int `bson:"auth_status"`}
可以看到phone字段后加了omitempty标签,表示当该字段为空的时候不插入。这还是会出现问题,那么既然还是会出问题为什么会想到这么解决呢?
这源于对Mysql的使用经验,习惯性的以为MongoDB和Mysql那样,对null的值会不做其索引。也就是说,在Mysql中,若在多条记录中Phone值为Null是被允许的。
上面那种做法,还是会报错,提示插入了重复的值,只不过这时不是空字符串,而是null。所以有时候就不要把Mysql那套拿来了,Mysql是可以的,但Mongo不行。mongo还是会对该条记录索引,即使该字段为被插入。
我喜欢看官方文档,下面给出MongoDB官方文档说明:
If a document does not have a value for the indexed field in a unique index, the index will store a null value for this document. Because of the unique constraint, MongoDB will only permit one document that lacks the indexed field. If there is more than one document without a value for the indexed field or is missing the indexed field, the index build will fail with a duplicate key error.
其实已经说得很清楚了,稍微会点英语应该都能看懂,下面还是给出翻译版:
如果文档没有唯一索引中索引字段的值,则索引将为此文档存储null值。由于唯一约束,MongoDB只允许一个缺少索引字段的文档。如果有多个文档没有索引字段的值或缺少索引字段,则索引构建将失败并出现重复键错误。
也就是说这个字段哪怕在文档中没有,那么该字段将会存null值,该字段上也不能同时出现两个null值,这就是为什么上面那种做法还是行不通的原因。
其实上面那种做法也打破了数据结构,虽然手机号未填,但数据库中也不应该缺少这个字段,尽管是非关系数据库,毕竟还得考虑下业务设计。
解决方式
是不是就没有解决方式了呢?当然有,Mongo提供了Sparse Index,被翻译为稀疏索引。下面是创建稀疏索引的例子:
db.getCollection("test").createIndex({"phone":1}, {sparse:true})
执行上面的语句后,不会去索引不存在phone字段的文档。也就是说存在才对其索引,那么此时和Unique索引结合起来就可以派上用场了。Unqiue是唯一,Sparse是存在才索引。所以,当phone或email为空的时候我们可以不将其插入这是可以实现的。
db.getCollection("test").createIndex({"phone":1}, {sparse:true,unique:true})
上面是是mongo shell语法,通常我们一般通过代码中建立索引,修改如下(当然User结构体中Phone字段omitempty标签还是要有的):
func init() { phoneIndex := mgo.Index{ Key: []string{"phone"}, Unique: true, Sparse: true, } col := db.Collection(&User{}) col.EnsureIndex(phoneIndex)}
但是这又正如我们前面说的那样,打破了数据原有的数据结构。哎,有得有得。当然我们还可以从业务层面去解决,比如注册时对其查询等操作,当然会耗一定性能,不管你是那空间换时间,还是拿时间换空间总得付出一个,别做一个太贪心的人。
access建立两个字段唯一索引_关于MongoDB唯一索引(Unique)的那些事相关推荐
- access建立两个字段唯一索引_数据库索引原理及优化
微信公众号:云计算通俗讲义 持续输出技术干货,欢迎关注! 通过本文你将了解: 概述 分类 索引底层实现原理 基本操作 索引失效 索引优化 01 概述 索引是帮助MySQL高效获取数据的排好序的数据结构 ...
- access建立两个字段唯一索引_面试官:谈谈你对mysql索引的认识?
引言 这篇我们就来谈谈关于索引方面的mysql面试题.还是老规矩,讲的是在Innodb存储引擎下的情形,毕竟我还真没用过Mysiam之类的存储引擎. ps:其实很早就想写了,一直偷懒! 其实这下面每个 ...
- mysql 添加唯一索引_浅谈Mysql索引
文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 我们都知道,数据库索引可以帮助我们更加快速的找出符合的数据,但是如果不使用索引,Mysql则会从第一条开始查询 ...
- mysql字段的区分度_详解MySQL索引长度和区分度之间的平衡,值得收藏
概述 前面我们讲了怎么去计算索引所占用的长度?那么换个方式想?索引又应该设置多少长度比较合理呢? 区分度与索引长度的权衡 首先索引长度和区分度是相互矛盾的, 索引长度太短,那么区分度就很低,吧索引长度 ...
- mysql单列索引和多列索引_浅谈MySQL索引优化
索引基础知识总结及常见索引优化手段 一.索引简介 什么是索引? MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构. 可以简单理解为"排好序的快速查找数据 ...
- mysql主键创建非聚集索引_什么是聚集索引,非聚集索引,索引覆盖,回表,索引下推...
聚集索引 我们先建如下的一张表 CREATE TABLE `student` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号',`name` var ...
- 覆盖索引与联合索引_浅析MySQL的索引覆盖和索引下推
写在前面 在MySQL数据库中,索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点,索引就是为了提高数据查询的效率.今天我们来聊聊在MySQL索引优化中两种常见的方式,索引覆盖和 ...
- 覆盖索引与联合索引_什么是覆盖索引?
前言 要搞明白覆盖索引首先就得明白主键索引和辅助索引的区别,以及查询时引擎的工作方式. 当然,以上都是基于innoDB引擎来说. 主键索引与辅助索引的区别 相信大家也了解过这方面的知识,这里就不展开了 ...
- mysql linux 使用索引_正确使用MySQL索引
MySQL之所以能够高效的检索数据,可以说全赖索引之功.在索引使用过程中,要注意一下几点. 1.MySQL在使用索引时候,采用的是最左匹配原则. 如果是单列索引,则很容易理解,若是多列索引,例如idx ...
最新文章
- html页面表格导出到excel总结
- Puppeteer + TypeScript 模拟 Ctrl + A 操作
- iOS NSTextAttachment - 图文混排
- iso镜像添加软件包_超薄Docker容器-减少Docker镜像大小的指南
- 消息队列MQ如何保证消息的幂等性
- centos PIL 安装
- c 语言 怎样编写图形窗口,「分享」C语言如何编写图形界面
- 面试鹅厂,我被虐的体无完肤。。。
- linux 串口是否可写,串口编程可写入不能读取 怎么解决
- 2016 杭州云栖大会随笔
- 微信添加表情提示过大怎么解决?GIF太大怎么变小?
- Byval和ByRef
- 计算机64位只有2g,电脑插了4G内存,但只有2G左右可以用,为什么 WIN7 64位
- c语言的源程序的后缀名是,C语言源程序文件的后缀名是()。
- 联手百度腾讯,恒大汽车押注智能化
- (学习记录)Win32开发之键盘
- 基于Visual Graph快速开发出电力系统
- Windows常用bat脚本打开目录或文件
- Python语言程序设计 (第11期) 期末测验: 课程水平综合测验
- apache ii评分和死亡率_APACHEⅢ、SAPSⅡ与APACHEⅡ评分系统对急诊内科危重患者病情评估的临床意义...
热门文章
- java冗余_Java使用lombok消除冗余代码的方法步骤
- CRMEB v4二开文档
- git批量删除没用的远程分支
- Linux7的ftp日志怎么看,centos7打开sftp操作日志
- 256qam调制星座图_5G调制怎么实现的?一文读懂
- 计算机科学讨论,第七章计算机科学讨论报告
- android 加减乘除计算器,【03-21求助】写一个简易计算器的安卓app,一按加减乘除就退出...
- mysql base64
- 【uni-app】动态计算图片高度且保持宽高比
- Java NIO之Selector