系列文章

三、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. Linux系列(37) - 源码包与RPM包区别(1)

    源码包是不能使用[service]命令来启动服务,因为源码包的安装位置由用户指定 源码包一般安装在: /usr/local/软件名/ ,源码包安装的服务,只能用绝对路径进行服务的管理 rpm包安装后, ...

  2. 深入HTML5第一天

    页面的title一般是30-40个字符:分别为主页,详情页,列表页  keywords:100个字符  description: em是:emphasize: 强调,着重  i:italic斜体的 : ...

  3. mogoose 创建数据库并增删改查

    下载 npm i mongoose -s 连接数据库 const mongoose = require("mongoose"); mongoose.connect(dbURL); ...

  4. Python语句,表达式的区别?

    参考了网上的文章,说 表达式的结果是值,对象 比如1+2, 是表达式 具体根据运算符不同有算术,逻辑,比较等等类型的表达式 语句是控制程序走向,不产生值 例如if/else等 参考: https:// ...

  5. 如何使用云效Flow做质量检测,保障高质量的交付速度

    使用云效Flow做质量检测,保障高质量的交付速度,云效「Flow」 提供代码扫描. 安全扫描和各种自动化测试能力,支持人工测试卡点.自动化验证卡点等多种质量红线,确保业务质量.云效流水线 Flow 流 ...

  6. Oracle实时数据抽取项目问题总结

    Oracle实时数据抽取项目问题总结 项目背景介绍 项目主要是将Oracle.MySQL.SQLServer.Db2等其他数据库的实时变更数据同步到其他异构数据库中.本篇文章主要是讨论oracle的实 ...

  7. Java 爬取 51job 数据 WebMagic实现

    Java 爬取 51job 数据 一.项目Maven环境配置 相关依赖 jar 包配置 <parent> <groupId>org.springframework.boot&l ...

  8. 设计 4 个线程,其中两个线程每次对 j 增加 1 ,另外两个线程对 j 每次减少 1 。写出程序。

    题目:设计 4 个线程,其中两个线程每次对 j 增加 1 ,另外两个线程对 j 每次减少 1 .写出程序. 代码实现 public class ThreadTest{ private int j; c ...

  9. netty 处理客户端连接

    Netty如何处理连接事件 上文讲了Netty如何绑定端口,现在我们来阅读下netty如何处理connect事件.上文我们说了NioEventLoop启动后不断去调用select的事件,当客户端连接时 ...

  10. Nginx安装及核心配置解析

    安装 使用yum进行安装 yum install -y nginx 查看nginx的安装位置 whereis nginx 启动测试 nginx 核心配置文件结构 读取Nginx自带的Nginx配置文件 ...