MySQL实战解析底层---怎么给字符串字段加索引

2023-05-16

目录

所谓前缀索引

前缀索引对覆盖索引的影响

其他方式


  • 所谓前缀索引

  • 现在,几乎所有的系统都支持邮箱登录,如何在邮箱这样的字段上建立合理的索引,是今天要讨论的问题
  • 假设,你现在维护一个支持邮箱登录的系统,用户表是这么定义的

  • 由于要使用邮箱登录,所以业务代码中一定会出现类似于这样的语句:

  • 从之前讲解索引的文章中,可以知道,如果 email 这个字段上没有索引,那么这个语句就只能做全表扫描
  • 同时,MySQL 是支持前缀索引的,也就是说,你可以定义字符串的一部分作为索引
  • 默认地,如果你创建索引的语句不指定前缀长度,那么索引就会包含整个字符串
  • 比如,这两个在 email 字段上创建索引的语句

  • 第一个语句创建的 index1 索引里面,包含了每个记录的整个字符串;
  • 而第二个语句创建的 index2 索引里面,对于每个记录都是只取前 6 个字节
  • 那么,这两种不同的定义在数据结构和存储上有什么区别呢?
  • 如图所示,就是这两个索引的示意图

  • 从图中你可以看到,由于 email(6) 这个索引结构中每个邮箱字段都只取前 6 个字节(即:zhangs)
  • 所以占用的空间会更小,这就是使用前缀索引的优势
  • 但这同时带来的损失是,可能会增加额外的记录扫描次数
  • 接下来再看看下面这个语句,在这两个索引定义下分别是怎么执行的

  • 如果使用的是 index1(即 email 整个字符串的索引结构),执行顺序是这样的
    • 1.从 index1 索引树找到满足索引值是’zhangssxyz@xxx.com’的这条记录,取得 ID2 的值;
    • 2.到主键上查到主键值是 ID2 的行,判断 email 的值是正确的,将这行记录加入结果集;
    • 3.取 index1 索引树上刚刚查到的位置的下一条记录,发现已经不满足email='zhangssxyz@xxx.com'的条件了,循环结束
  • 如果使用的是 index2(即 email(6) 索引结构),执行顺序是这样的
    • 1.从 index2 索引树找到满足索引值是'zhangs'的记录,找到的第一个是 ID1;
    • 2.到主键上查到主键值是 ID1 的行,判断出 email 的值是’zhangssxyz@xxx.com’,这行记录丢弃;
    • 3.取 index2 上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出 ID2,再到 ID 索引上取整行然后判断,这次值对了,将这行记录加入结果集;
    • 4.重复上一步,直到在 index2 上取到的值不是’zhangs’时,循环结束
  • 在这个过程中,要回主键索引取 4 次数据,也就是扫描了 4 行
  • 通过这个对比,你很容易就可以发现,使用前缀索引后,可能会导致查询语句读数据的次数变多
  • 但是,对于这个查询语句来说,如果你定义的 index2 不是 email(6) 而是 email(7)
  • 也就是说取 email 字段的前 7 个字节来构建索引的话,即满足前缀’zhangss’的记录只有一个,也能够直接查到 ID2,只扫描一行就结束了
  • 也就是说使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本
  • 于是就有个问题:当要给字符串创建前缀索引时,有什么方法能够确定我应该使用多长的前缀呢?
  • 实际上,在建立索引时关注的是区分度,区分度越高越好
  • 因为区分度越高,意味着重复的键值越少
  • 因此可以通过统计索引上有多少个不同的值来判断要使用多长的前缀
  • 首先,你可以使用下面这个语句,算出这个列上有多少个不同的值:

  • 然后,依次选取不同长度的前缀来看这个值,比如要看一下 4~7 个字节的前缀索引,可以用这个语句

  • 当然,使用前缀索引很可能会损失区分度,所以你需要预先设定一个可以接受的损失比例,比如 5%
  • 然后,在返回的 L4~L7 中,找出不小于 L * 95% 的值,假设这里 L6、L7 都满足,你就可以选择前缀长度为 6
  • 前缀索引对覆盖索引的影响

  • 前面说了使用前缀索引可能会增加扫描行数,这会影响到性能
  • 其实,前缀索引的影响不止如此,再看一下另外一个场景
  • 先来看看这个 SQL 语句:

  • 与前面例子中的 SQL 语句:

  • 相比,这个语句只要求返回 id 和 email 字段
  • 所以,如果使用 index1(即 email 整个字符串的索引结构)的话,可以利用覆盖索引,从 index1 查到结果后直接就返回了,不需要回到 ID 索引再去查一次
  • 而如果使用 index2(即email(6) 索引结构)的话,就不得不回到 ID 索引再去判断 email 字段的值
  • 即使你将 index2 的定义修改为 email(18) 的前缀索引,这时候虽然 index2 已经包含了所有的信息,但 InnoDB 还是要回到 id 索引再查一下,因为系统并不确定前缀索引的定义是否截断了完整信息
  • 也就是说,使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素
  • 其他方式

  • 对于类似于邮箱这样的字段来说,使用前缀索引的效果可能还不错
  • 但是,遇到前缀的区分度不够好的情况时,要怎么办呢?
  • 比如,我们国家的身份证号,一共 18 位,其中前 6 位是地址码,所以同一个县的人的身份证号前 6 位一般会是相同的
  • 假设你维护的数据库是一个市的公民信息系统,这时候如果对身份证号做长度为 6 的前缀索引的话,这个索引的区分度就非常低了
  • 按照前面说的方法,可能你需要创建长度为 12 以上的前缀索引,才能够满足区分度要求
  • 但是,索引选取的越长,占用的磁盘空间就越大,相同的数据页能放下的索引值就越少,搜索的效率也就会越低
  • 那么,如果能够确定业务需求里面只有按照身份证进行等值查询的需求,还有没有别的处理方法呢?
  • 这种方法,既可以占用更小的空间,也能达到相同的查询效率
  • 答案是,有的
  • 第一种方式是使用倒序存储
  • 如果你存储身份证号的时候把它倒过来存,每次查询的时候,你可以这么写

  • 由于身份证号的最后 6 位没有地址码这样的重复逻辑,所以最后这 6 位很可能就提供了足够的区分度
  • 当然了,实践中你不要忘记使用count(distinct) 方法去做个验证
  • 第二种方式是使用 hash 字段
  • 你可以在表上再创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引

  • 然后每次插入新记录的时候,都同时用crc32()这个函数得到校验码填到这个新字段
  • 由于校验码可能存在冲突,也就是说两个不同的身份证号通过crc32()函数得到的结果可能是相同的,所以你的查询语句where部分要判断id_card的值是否精确相同

  • 这样,索引的长度变成了 4 个字节,比原来小了很多
  • 接下来再一起看看使用倒序存储和使用 hash 字段这两种方法的异同点
  • 首先,它们的相同点是,都不支持范围查询
  • 倒序存储的字段上创建的索引是按照倒序字符串的方式排序的,已经没有办法利用索引方式查出身份证号码在[ID_X, ID_Y]的所有市民了
  • 同样地,hash 字段的方式也只能支持等值查询
  • 它们的区别,主要体现在以下三个方面:
    • 1.从占用的额外空间来看,倒序存储方式在主键索引上,不会消耗额外的存储空间,而 hash 字段方法需要增加一个字段
    • 当然,倒序存储方式使用 4 个字节的前缀长度应该是不够的,如果再长一点,这个消耗跟额外这个 hash 字段也差不多抵消了
    • 2.在 CPU 消耗方面,倒序方式每次写和读的时候,都需要额外调用一次 reverse 函数,而 hash 字段的方式需要额外调用一次 crc32() 函数
    • 如果只从这两个函数的计算复杂度来看的话,reverse 函数额外消耗的 CPU 资源会更小些
    • 3.从查询效率上看,使用 hash 字段方式的查询性能相对更稳定一些
    • 因为 crc32 算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近 1
    • 而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL实战解析底层---怎么给字符串字段加索引 的相关文章

  • Spring Aop通知注解的执行顺序

    spring4和spring5有所不同 spring4没异常有异常执行顺序从上往下 64 Around通知前 64 Aroud通知前 64 Before通知 64 Before通知业务代码 64 After通知 64 Around通知后 6
  • vcruntime140_1.dll无法继续执行代码如何修复?

    vcruntime140 1 dll是电脑系统动态链接中非常重要的文件 xff0c 主要用于处理各种程序 每台计算机上都有相当多的DLL文件 xff0c 不同的程序会使用不同的DLL文件 电脑系统如果丢失dll文件 xff0c 会导致很多软
  • Linux基础指令的基本操作(一)

    文章目录 Linux用户管理 xff1a 1 adduser添加用户2 passwd修改用户密码3 userdel删除用户 其他指令alias指令 取别名 whoami指令man指令 重要 bc指令unamefreedf h Linux 访
  • Linux 权限(二)权限掩码 粘滞位 详细

    文章目录 Linux权限的概念Linux权限管理01 文件访问者的分类 xff08 人 xff09 02 文件类型和访问权限 xff08 事物属性 xff09 拥有者 xff0c 所属组 xff0c other vs root 和普通用户a
  • Linux——基础IO

    文章目录 先来段代码回顾C文件接口写文件读文件输出信息到显示器 xff0c 你有哪些方法 默认打开的三个流 stdin amp stdout amp stderr系统接口openclosewriteread文件描述符fd文件描述符的分配规则
  • boost字符串库简单使用

    boost字符串库简单使用 说明用法大小写转换字符串分割去掉字符串两边空格替换字符串 replace first replace first copy 说明 写c 43 43 程序的时候 xff0c 虽然std string有数百余函数 x
  • 线程安全下单例模式

    文章目录 什么是单例模式单例模式的特点定义对象的本质什么时候创建对象饿汉实现方式和懒汉实现方式饿汉方式实现单例模式懒汉方式实现单例模式懒汉方式实现单例模式 线程安全版本 什么是单例模式 单例模式是一种 经典的 常用的 常考的 设计模式 单例
  • Linux 线程池

    文章目录 线程池的定义使用线程池的原因基于POSIX实现的线程池基于block队列的线程池实现基于ring队列的线程池实现 设计单例模式线程池 线程池的定义 线程池就一堆已经创建好的任务线程 xff0c 初始它们都处于空闲等待状态 xff0
  • 魔都,3年,程序员到CTO

    过一个平凡无趣的人生实在太容易了 xff0c 你可以不读书 xff0c 不冒险 xff0c 不运动 xff0c 不写作 xff0c 不外出 xff0c 不折腾 但是 xff0c 人生最后悔的事情就是 xff1a 我本可以 陈素封 我可以 在
  • TCP协议

    文章目录 1 保证可靠性机制1 1 确认应答机制1 1 1确认应答机制概念1 1 2常规确认应答的工作方式1 1 3报文按序到达1 1 4 如何确认历史数据被收到1 1 5 16位序号和16确认序号 xff08 字段讲解 xff09 tcp
  • 1 对数器,二分查找,

    文章目录 对数器二分查找 1 有序序列二分查找 2 在一个有序数组中 xff0c 找 lt 61 某个数最右侧的位置 3 在一个有序数组中 xff0c 找 gt 61 某个数最左侧的位置 4 无序序列二分查找 xff0c 求局部最小值 对数
  • 2 异或位运算大厂必刷题

    文章目录 如何不用额外变量交换两个数一个数组中有一种数出现了奇数次 xff0c 其他数都出现了偶数次 xff0c 怎么找到并打印这种数怎么把一个int类型的数 xff0c 提取出最右侧的1来怎么把一个int类型的数 获取位数为1的数量一个数
  • 链表,栈,队列,递归行为,哈希表,有序表

    文章目录 链表1 单链表 双链表的反转2 删除链表中指定的值 队列1 数组循环队列的实现2 双向链表实现双端队列 栈1 用数组实现栈 栈和队列的面试题1 实现最小栈2 两个栈实现一个队列3 两个队列实现一个栈4 用栈实现图的广度优先遍历5
  • 搭建Zabbix6.0版本

    Zabbix简介 Zabbix是一个企业级的开源分布式监控解决方案 xff0c 由C语言编写而成的底层架构 xff08 server端和agent端 xff09 xff0c 由一个国外的团队持续维护更新 xff0c 软件可以自由下载使用 x
  • Linux--网络服务器配置步骤详情【1】

    目录 一 配置ip地址 二 配置yum服务器 三 配置安装nfs服务器 1 第一台机 xff1a 2 第二台机 xff1a 四 安装配置samba服务器 五 安装配置DHCP 一 配置ip地址 root 64 wenjian vi etc
  • vscode提取拓展时出错。XHR failed

    vscode提取拓展时出错 XHR failed huas weew12的博客 CSDN博客 提取扩展时出错 转载 这这人家的步骤操作 果然就好了
  • python天气语音播报

    今天的小项目是一个天气播报 xff0c 项目效果是点击运行就读出今天的天气 那么我们可以分两步走 xff0c 第一个 xff1a 先爬取到今天的天天气内容 xff0c 第二步 xff1a 电脑读出今天的天气内容 想要电脑读出内容 xff0c
  • Linux配置SSH远程登录管理

    目录 一 SSH协议 1 SSH简介 2 SSH的优点 3 SSH远程控制软件及服务 二 SSH远程管理配置 1 配置OpenSSH服务端 2 使用SSH客户端软件 xff08 1 xff09 SSH远程登录 xff08 2 xff09 s
  • Linux系统防火墙firewalld

    目录 一 firewalld概述 二 firewalld和iptables的关系 三 firewalld区域的概念 四 firewalld数据处理流程 五 firewalld检查数据包源地址的规则 六 firewalld防火墙的配置种类 1
  • ubuntu18.04忘记密码后,如何重置密码的方法

    ubuntu18 04安装在VMware虚拟上 ubuntu18 04忘记密码后 xff0c 如何重置密码 xff1f 重启系统后 xff0c 当跳出如下图所示画面时 xff0c 按住Shift键不放 xff0c 等待 2 但出现如下图所示

随机推荐

  • Cloudflare 小记

    url xff1a https cn airbusan com content individual 五秒盾打开后一般会出现这个页面 xff0c 然后让你点击确认你是不是真人 xff0c 点击成功后会跳往所访问的url页面 有时候不会出现这
  • 2021.11.17 指针引用数组(指针+1,指针-1以及书写格式)

    例如 xff1a int arr 10 61 1 2 3 4 5 6 7 8 9 10 int p 61 arr int q 61 amp arr 0 1 p 和 q 表示的都是一样的 xff0c 表示的都是数组首元素的地址 xff0c 只
  • 超详细的vscode 配置FTP,并本地编辑

    废话少说 xff0c 直接上步骤 xff1a 搜索sftp插件并安装 xff1b 安装成功之后 ctrl 43 shift 43 p 搜索sftp config设置内容 没有的需要自己加 xff0c 有的可以不用加 xff1b 34 nam
  • Python求1+2+3+...+100的值,计算平方根的两个代码程序

    目录 前言 一 求1 43 2 43 3 43 43 100的值 1 实现的功能 2 代码程序 3 运行截图 二 计算平方根 1 实现的功能 2 代码程序 3 运行截图 前言 1 因多重原因 xff0c 本博文由两个程序代码部分组成 xff
  • Python求1+2+3+...+100的值,计算自然数的立方和的两个程序代码

    目录 前言 一 求1 43 2 43 3 43 43 100的值 1 实现的功能 2 代码程序 3 运行截图 二 计算自然数的立方和的 1 实现的功能 2 代码程序 3 运行截图 前言 1 因多重原因 xff0c 本博文由两个程序代码部分组
  • Go基本数据类型与string类型互转

    一 基本数据类型转string类型 方法一 xff1a fmt Sprintf 34 参数 34 表达式 1 官方解释 xff1a Sprintf根据format参数生成格式化的字符串并返回该字符串 func Sprintf format
  • linux下如何设置开机自启(这里以seata服务为例)

    1 编写启动脚本 xff0c 大部分都是相同的 xff0c 但是有些程序可能略要修改 Unit Description 61 Seata Server After 61 network target Service User 61 root
  • MIUI12.5系统精简列表更新版200多个包,ADB卸载

    系统MIUI12 5 6 xff0c 无ROOT无面具没破解 xff0c 仅使用ADB工具箱 设备卸载后经过重启测试是否卡米 xff0c 这些都不会卡米 另外要说 xff0c 有些卸载不会卡米 xff0c 但是功能会失效 xff0c 比如
  • kali安装卡在simple-cdd不动?在右下角,有个小小的符号,找到网络适配器,然后断掉,很快就安装好了。

  • 两种方式为button元素注册点击事件,this指向

    两种方式 xff1b 第一种指向button xff0c 第二种 指向window
  • 强化学习实战——Q learning 实现倒立摆

    倒立摆参数以及数学模型 首先是写一个倒立摆的AGENT模型 pendulum env py import numpy as np import matplotlib pyplot as plt import matplotlib impor
  • dependencies.dependency

    依赖包有两个 xff0c 根据最下一行的提示找到项目的pom xml文件找到依赖
  • Vue3---语法初探

    目录 hello world 实现简易计时显示 反转字符串 显示隐藏 了解循环 了解双向绑定实现简易记事 设置鼠标悬停的文本 组件概念初探 xff0c 进行组件代码拆分 hello world 最原始形态 xff0c 找到 id 为 roo
  • MySQL实战解析底层---普通索引和唯一索引,应该怎么选择

    目录 前言 查询过程 更新过程 change buffer 的使用场景 索引选择和实践 change buffer 和 redo log 前言 在不同的业务场景下 xff0c 应该选择普通索引 xff0c 还是唯一索引 xff1f 假设你在
  • 准备离开:致消散的梦想

    学到现在基本都是悲剧以前的队友现在大多放弃了初心以前的好学长现在摆烂和失败开学时的场景再也见不到了大一开学开启OJ xff0c 那是一个永远绚丽的夜晚不管是学长还是同学 xff0c 都在那时期待未来 xff0c 欲力竭以圆其说而不是现在的颓
  • MySQL实战解析底层---MySQL为什么有时候会选错索引

    目录 前言 优化器的逻辑 索引选择异常和处理 前言 在 MySQL 中一张表其实是可以支持多个索引的但是你写 SQL 语句的时候 xff0c 并没有主动指定使用哪个索引也就是说 xff0c 使用哪个索引是由 MySQL 来确定的不知道你有没
  • 二叉搜索树

    目录 定义简介 查找结点 插入结点 删除结点 排序 二叉搜索树的效率 二叉搜索树的退化 二叉搜索树常见应用 定义简介 二叉搜索树 Binary Search Tree 满足以下条件 xff1a 1 对于根结点 xff0c 左子树中所有结点的
  • AVL 树

    目录 介绍 结点高度 结点平衡因子 AVL 树旋转 右旋 左旋 先左后右 先右后左 旋转的选择 插入结点 删除结点 查找结点 AVL 树典型应用 介绍 在进行多次插入与删除操作后 xff0c 二叉搜索树可能会退化为链表此时所有操作的时间复杂
  • 红黑树(更高级的二叉查找树)

    目录 介绍及性质 红黑树的基本定义 黑高度 时间复杂度 接近于 平衡 操作 红黑树的旋转 红黑树中插入新结点 红黑树中删除结点 红黑树与AVL树的区别 介绍及性质 红黑树 xff08 R B TREE xff0c 全称 xff1a Red
  • MySQL实战解析底层---怎么给字符串字段加索引

    目录 所谓前缀索引 前缀索引对覆盖索引的影响 其他方式 所谓前缀索引 现在 xff0c 几乎所有的系统都支持邮箱登录 xff0c 如何在邮箱这样的字段上建立合理的索引 xff0c 是今天要讨论的问题假设 xff0c 你现在维护一个支持邮箱登