Mysql如何给字符串添加索引(前缀索引)
在日常开发中,我们经常给字符串添加索引,那么给字段添加索引有什么技巧吗,我们看看下面的例子,我们给一个邮箱添加索引,应该如何添加呢
看看下面这条sql
select * from user where email ='jiepi@qq.com'
如果我们不添加索引,肯定是要进行全表扫描的,那么我们如何添加呢有两种方式
alter table user add index index1(email)
alter table user add index index2(email(6))
上面两种方式都是在添加索引,不同点就是第二种添加的仅仅是邮箱的前缀索引,那么他的结构表现如下图
index2每个索引中仅仅存储了字段的前6个字符,而index1存储了整个字符串,我们分别在不同索引下执行下面的语句
select id,name,email from user where email='zhangsan@qq.com'
如果使用index1,他的执行过程如下
- 在index1中找到符合条件的记录,获取id=5
- 然后使用id=1,在主键索引上获取整行记录
- 在index1寻找下一条记录,直到发现不满足位置,循环结束
如果使用index2,他的执行过程如下
- 在index2中找到符合条件的值,获取到id=1
- 然后在主键索引中找到id=1的数据,发现不符合
- 在index2继续寻找,id=2,然后在主键上找到行记录,发现不符合
- 循环上面步骤,直到符合的记录
我们发现使用index2虽然占用的空间小,但是他对搜索的性能没有更好的提高,而是要多扫描几行记录。
是不是发现前缀索引不是很好呢,然而并不是的,我们如果把索引的长度修改成8,然后在index2中仅仅找到一条符合记录,因此只需要扫描一行就够了。
于是,我们发现选择合适的前缀长度,既可以节省空间,也可以不用增加更多的查询成本,
那么如何选择合适的前缀长度呢
建立索引之前,我们要关注字段的区分度,区分度越大,性能越高,意味着重复的值就越少。查看某列的值不同的值
select count(distinct email) as L from user
然后,我们分别取不同长度的前缀,比如我们看一下4-7个字节的前缀索引
select
count(distinct left(email,4)) as l4
count(distinct left(email,5)) as l5
count(distinct left(email,6)) as l6
count(distinct left(email,7)) as l7
from user
当前使用前缀索引会丢失区分度,索引我们要预定一个可以接受的损失比例,比如5%,然后,计算出L4-L7中,找到不小于L*95%。假设L6,L7,满足,你就可以选择长度为6.
前缀索引对覆盖索引的影响
上面我们分析了,前缀索引影响扫描的行数,其实,他也是会影响覆盖索引的,正如下面例子
select id,email from user where email='zhangsan@qq.com'
select id,name,email from user where email='zhangsan@qq.com'
如果我们只要返回id,email,因此使用index1索引,找到符合记录利用覆盖索引,直接返回索引的值,就可以满足需求,但是如果我们使用index2,即使我们使用email(8)可以找到唯一一行数据,但是我们还是要进行那id的值去主键索引判断是不是email的值,再不济,我们使用email(18),完全包含字段的长度,但是我们依然要回表查找主键索引,因为系统并确定前缀索引是否有截断完成信息,
总结就是使用前缀索引,就无法使用覆盖索引。
其他方式
对于邮箱类型的字段,使用前缀索引是一个不错的选择,但是我们要是遇到前缀区分度不大的字段应该怎么办呢,
第一种,我们可以使用倒序存储,如果存储身份证,一般身份中前6位,一个省的值都是一样,而后几位区分度就还可以,索引我们可以使用下面语句查询
select name from user where id_card=reverse('id_card_string')
第二种,我们使用hash字段,我们创建一个字段,直接把身份证的值进行hash,存储在这个字段中,同时建立索引,由于可能存在多个身份证可能有一样的hash值,因此还要判断id_card的值是否准确
select name from user where id_card_crc=crc32('id_card_string') and id_card='id_card_string'
上面两种共同点就是不支持范围查询,他们的主要区别如下
- 从占用的空间方面说,倒序存储方式在主键上不会消耗额外的空间,而hash索引要所创建一个字段,但是如果倒排存储长度过长的话,消耗的空间和hash差不多
- 两种方式都要使用额外函数,如果从两个函数的复杂度说的话,reverse函数额外消耗的CPU小点
- 查询效率上,hash字段的方式更稳定一些,虽然可能有冲突,但是这种概率很小,且认为平均扫描一行,而倒序存储毕竟还要使用前缀索引方式,也就是会增加扫描的行数
如果文章对您有一丝丝帮助,麻烦点个关注,也欢迎转发点赞,谢谢
- 深入浅出事件流处理NEsper(三)
- 用Flex模拟智能手机表单输入的自动放大功能
- c#4.0中的动态编程
- 手把手教 Vue-环境搭建
- 马化腾:通向互联网未来的七个路标
- 微信小程序,让生活不一样
- rsync+inotify实时同步环境部署记录
- 常用rsync命令操作梳理
- 无人驾驶系列——深度学习笔记:Tensorflow基本概念
- Android Fragment应用实战
- c#4.0中的不变(invariant)、协变(covariant)、逆变(contravariant)小记
- 用于.NET的可移植HTTP客户端
- 我是如何利用CSRF Get DedeCms Shell的
- asp.net webform中submit按钮使用不当很容易犯的一个错误
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- 三阴性乳腺癌表达数据分析笔记之TNBC定义
- JVM和操作系统的关系是什么?
- PostgreSQL 查询注释
- Python虚拟环境安装与配置
- 2019 年第十届蓝桥杯省赛 B组 C++超详细题解
- 五. css 布局之 position(定位)
- 【译】Rust与智能指针
- 根据坐标在基因组上面拿到碱基序列来设计引物
- 18款Webpack插件,总会有你想要的!
- Linux下如何查看硬件信息?
- 最通俗易懂的一篇文章了解JVM、JRE、JDK的关系是什么?
- 六. CSS 样式补充之 font & background
- 七 .Html的表格
- rollup + typescript 构建 ts 包
- node 写爬虫,原来这么简单