系列文章

三、MySQL强人“锁”难《死磕MySQL系列 三》

四、S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》

五、如何选择普通索引和唯一索引《死磕MySQL系列 五》

六、五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》

相信大多数小伙伴跟咔咔一样,给字符串添加索引从未设置过长度,今天就来聊聊如何正确的给字符串加索引。

一、如何建立索引

大多数系统都会存在用户表,并且系统初始设计使用了手机号码登录的。

这是产品提出了一个需求,让系统也可以支持邮箱登录。

肯定知道的是若不给邮箱字段添加索引执行查询是会全表扫描。

此时你心里窃喜这还不简单,给邮箱字段加个索引完事呗!但要做到复杂的需求做好,简单的需求要最好,减轻一切对系统的压力。

此时的你拿起键盘就执行了alter table table_name add index idx_field (field)

有部分小伙伴不喜欢命令行创建索引,喜欢使用phpmyadmin工具来操作MySQL,那么在建立索引时有没有发现后边可以设置大小呢?

通过上边给大家展示的图片知道字符串建立索引是可以定义长度的,那么两者有什么区别。

使用命令行alter table table_name add index idx_field (field)直接创建的索引默认是包含整个字符串。

若这样执行就指定了索引前缀长度alter table table_name add index idx_field (field(6))

一图解千愁,看一下建立的两个索引结构是什么样的。

索引一结构图


索引一结构图

索引二结构图


索引二结构图

从图中可以看到,指定了索引长度为6那么就只取邮箱字段的前6个字段,相对索引包含整个字符串来说每个节点存储的数据会更多。

索引那篇文章也给大家说了建立索引在合适的范围内越小越好。

万物皆两面,有坏就有好,第六期文章误选索引的因素之一就是扫描行数。

索引长度减少带来的影响就是索引基数变大,从而增加额外的扫描记录数(执行explain的row字段)。

此时要执行select id,name,email from mac_user where email='1397393964@qq.com';

给整个字符串添加索引执行流程

1、从email索引树找到满足1397393964@qq.com的记录,得到主键ID为1

2、根据ID为1到主键索引树找到这条记录并判断email是否正确,将这行记录假如结果集。

3、重复第一步,直到不满足查询条件,循环结束。

指定索引长度执行流程

1、从email索引树找到满足139739的记录,得到主键ID为1

2、根据ID为1到主键索引树找到这条记录并判断email不正确,丢弃这行记录。

3、在email索引树找刚刚查询的下一条记录,发现还是139739,去除ID2,再到ID的索引树进行判断,当值对后加入结果集。

4、再继续重复上一步,直到不满足查询条件,循环结束。

结论

在模拟执行流程过程中很容易就发现,使用前缀索引会导致读取数据的次数增加,那是不是就代表使用前缀索引会增加查询代价呢?

肯定不是的,试想此时定义的长度是6那么设置为7或者8呢!是不是会好很多,图中的案例为了方便设置了三个一样的数据,但实际情况基本不会出现这样的情况。

建立索引关注的是区分度,只有区分度越高,重复值就越少,查询效率就越高。

所以使用前缀索引,只要定义好长度,就可以坐到既节省空间,又不用额外增加太多的查询代价。

二、创建索引如何确定使用多长的前缀

MySQL中关键词distinct可以返回本列不同的结果集。

例如查询email列有多少个不同的值select count(distinct email) as num from mac_user。

如何计算列不同前缀有多少行

结合MySQL自带的函数left来实现,例如select count(distinct left (email,4)) as num4 from mac_user,截取email的前四个字符串计算有多少行。

再用这个值去除总数得到的就是比例,根据业务情况来判断多少比例可以。

三、使用前缀索引的影响

使用前缀索引会增加扫描行数,同时也会使覆盖索引失效。

为什么会影响覆盖索引?

若执行语句为select id,email from mac_user where email = '1397393964@qq.com'

使用整个字符串索引结构查询可以使用覆盖索引,从email索引获取到结果就直接返回了,不用再进行回表。

若使用前缀索引在email索引获取到结果后还需要回到id索引在查一下判断查询的email的值是否正确。

哪怕是设置了大于了email的长度也会回表再进行判断,因为MySQL并不知道定义的前缀是否截取了完整信息。

结论

使用前缀索引会增加扫描行数,同样也使用不到覆盖索引。这个因素是你选择是否使用前缀索引要考虑的一个因素。

如果你不知道使用前缀索引还是全字符串索引,本地进行测试选一个合适的方案上到生产环境即可。

四、如何把不可以变为可以使用

假设身份认证系统存储的是身份证号,应该都知道身份证号前6位是地址码,同县的身份证号前6位一般是一样的。

这样使用前缀索引的话区分度会十分低,不但没有起到加速查询的作用,反而会造成索引区分度不大影响查询性能。

若把索引长度越长则每个节点存放的索引值就越少,查询效率也会变的低效。

如果解决这种场景

第一种方案

存储数据时将数据倒叙存储,查询时在正序处理一下即可

第二种方案

在表中新增一个字段,存储数据的hash值,给hash添加前缀索引。

区别

使用这两种方案共同点都不支持范围查询,都只能等值查询。

从占用空间来看:倒叙方式不会增加额外的存储空间,hash会增加一个字段。两者在空间不相上下

从CPU消耗来看:倒叙需要使用函数reverse,hash需要使用crc32 ,reverse消耗会小

从查询效率来看:hash查询更稳定,crc32计算的值虽有冲突但概率非常小,基本每次查询的平均扫描行数接近1。而倒叙使用的前缀索引方式,还会增加扫描行数。

五、总结

直接给字符串创建占用空间。

创建前缀索引,节省空间,会增加扫描行数,无法使用覆盖索引。

倒叙存储,创建前缀索引解决区分度不大的问题。

使用hash方式,查询稳定,不支持范围查询。

坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念。愿文章在偌大的互联网上能给你带来一点帮助,我是咔咔,下期见。

字符串可以这样加索引,你知吗?《死磕MySQL系列 七》的更多相关文章

  1. 为什么MySQL字符串不加引号索引失效?《死磕MySQL系列 十一》

    群里一个小伙伴在问为什么MySQL字符串不加单引号会导致索引失效,这个问题估计很多人都知道答案.没错,是因为MySQL内部进行了隐式转换. 本期文章就聊聊什么是隐式转换,为什么会发生隐式转换. 系列文 ...

  2. 如何选择普通索引和唯一索引《死磕MySQL系列 五》

    系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强 ...

  3. 五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》

    系列文章 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强人"锁"难<死磕MySQL系列 三> 四.S 锁与 X 锁的 ...

  4. mysql系列七、mysql索引优化、搜索引擎选择

    一.建立适当的索引 说起提高数据库性能,索引是最物美价廉的东西了.不用加内存,不用改程序,不用调sql,只要执行个正确的'create index',查询速度就可能提高百倍千倍,这可真有诱惑力.可是天 ...

  5. MySQL 笔记整理(11) --怎么给字符串字段加索引?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 11) --怎么给字符串字段加索引? 日常工作中的登录系统,你很可能会使 ...

  6. MySQL:字符串字段加索引

    1. 使用方式 1.1 全字段加索引 给整个字段加索引,索引存储整个字段的值. 数据量较小时,查询成本高,准确度高: 数据量较大时,比较耗费空间: 1.2 前缀索引 MySQL支持前缀索引,可以定义字 ...

  7. Mysql性能优化:如何给字符串加索引?

    导读 现代大部分的登录系统都支持邮箱.手机号码登录两种方式,那么如何在邮箱或者手机号码这个字符串上建立索引才能保证性能最佳呢? 今天这篇文章就来探讨一下在Mysql中如何给一个字符串加索引才能达到性能 ...

  8. 总结:如何使用redis缓存加索引处理数据库百万级并发

    前言:事先说明:在实际应用中这种做法设计需要各位读者自己设计,本文只提供一种思想.准备工作:安装后本地数redis服务器,使用mysql数据库,事先插入1000万条数据,可以参考我之前的文章插入数据, ...

  9. 使用redis缓存加索引处理数据库百万级并发

    使用redis缓存加索引处理数据库百万级并发 前言:事先说明:在实际应用中这种做法设计需要各位读者自己设计,本文只提供一种思想.准备工作:安装后本地数redis服务器,使用mysql数据库,事先插入1 ...

随机推荐

  1. windows日志查看与清理

    日志查看 (1) 启动Windows实验台,点击:开始 - 控制面板 - 管理工具 - 事件查看器. (2) 应用程序日志.安全日志.系统日志.DNS日志默认位置:%sys temroot%\syst ...

  2. vue 熟悉项目结构 创建第一个自己的组件

    * vue开发环境搭建 * 项目入口文件 ./src/main.js // The Vue build version to load with the `import` command // (ru ...

  3. 腾讯云centos7.5安装jdk1.8

    手动解压安装包方法 在user目录下新建java文件夹 cd /usr/ mkdir java 把jdk安装包移动到java目录下 我已经提前下载jdk的tar包 mv jdk-8u251-linux ...

  4. 简述编写Django应用的基本步骤

    (1)创建项目,cd到一个你想要放置你代码的目录.Django -admin startproject mysite. Django project即一个Django项目实例需要的设置项的集合,包括数 ...

  5. english note [6.3to6.9]

    6.3 http://www.51voa.com/VOA_Special_English/pakistan-town-struggles-with-rise-in-hiv-infections-821 ...

  6. P4201-[NOI2008]设计路线【结论,树形dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P4201 题目大意 给出\(n\)个点的一棵树开始所有边都是白色,选出若干条没有公共点的路径将上面所有边变为黑色. ...

  7. WPF进阶技巧和实战02-布局

    窗体 无边框 窗体无边框(最大化及标题位置)WindowStyle="None" 窗体透明 AllowsTransparency="True",必须设置窗体无边 ...

  8. HCNP Routing&Switching之BGP基础

    前文我们了解了路由注入带来的问题以及解决方案相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15362604.html:今天我们来学习下新的路由协议BG ...

  9. Unity——可复用背包工具

    Unity可复用背包工具 Demo展示 设计思路 游戏中有非常多的背包样式,比如玩家道具背包,商城,装备栏,技能栏等:每个形式的背包都单独写一份逻辑会非常繁琐,所以需要有一套好用的背包工具: 这些背包 ...

  10. Kubernetes全栈架构师(资源调度下)--学习笔记

    目录 StatefulSet扩容缩容 StatefulSet更新策略 StatefulSet灰度发布 StatefulSet级联删除和非级联删除 守护进程服务DaemonSet DaemonSet的使 ...