系列文章

三、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. Jvm调优理论篇

    Jvm实战调优 OOM(Out Of Memory) 内存溢出错误 ps:由于Java虚拟机有许多实现,本文主要阐述的是OpenJDK的HotSpot虚拟机,JDK版本是8. 一.首先要明白造成OOM ...

  2. 详细的vsftpd配置

    环境:CentOS 5.0 操作系统一.安装:1.安装Vsftpd服务相关部件:[root@KcentOS5 ~]# yum install vsftpd*Dependencies Resolved= ...

  3. P4457-[BJOI2018]治疗之雨【期望dp,高斯消元】

    正题 题目链接:https://www.luogu.com.cn/problem/P4457 题目大意 开始一个人最大生命值为\(n\),剩余\(hp\)点生命,然后每个时刻如果生命值没有满那么有\( ...

  4. Stream之高级函数

    上回文说到了有关Stream一些数学函数的用法.今天来说下Stream一些高级的函数用法,这些函数在日常工作中也是必不可少的,测试数据还是引用上一篇的数据. Map 这个方法我个人称之为转换函数,把一 ...

  5. null与undefined到底有啥区别?

    话不多说,直接先上结论: null 和 undefined 基本相同,只有细微差别 null 是表示缺少的标识,指示变量未指向任何对象,转为数值为 0 undefined 表示 "缺少值&q ...

  6. 学校选址(ArcPy实现)

    一.背景 合理的学校空间位置布局,有利于学生的上课与生活.学校的选址问题需要考虑地理位置.学生娱乐场所配套.与现有学校的距离间隔等因素,从总体上把握这些因素能够确定出适宜性比较好的学校选址区. 二.目 ...

  7. sql提示1055 不让你group by

    是不是突然写好的sql语句 部署上去就 Expression #2 of SELECT list is not in GROUP BY clause and containsnonaggregated ...

  8. 洛谷3244 落忆枫音 (拓扑图dp+式子)

    题目大意就是 给你一个DAG 然后添加一条边\(x->y\) ,询问以1为根的生成树的个数 QWQ 首先假设没有添加的边 答案就应该是 \[ans=\prod_{i=1}^{n} in[i] \ ...

  9. noip2017D1T3逛公园(拓扑图上dp,记忆化搜索)

    QWQ前几天才刚刚把这个D1T3写完 看着题解理解了很久,果然我还是太菜了QAQ 题目大意就是 给你一个n个点,m条边的图,保证1能到达n,求从1到n的 (设1到n的最短路长度是d)路径长度在[d,d ...

  10. 一文弄懂CGAffineTransform和CTM

    一文弄懂CGAffineTransform和CTM 一些概念 坐标空间(系):视图(View)坐标空间与绘制(draw)坐标空间 CTM:全称current transformation matrix ...