场景引入

假设现在维护一个支持邮箱登录的系统,用户表定义如下:

create table SUser(ID bigint unsigned primary key,email varchar(64), ... )engine=innodb;

由于登录方式为邮箱,那么一定会有下面这样的业务:

select f1,f2 from SUser where email='xxx';

对于上述语句,可以不对email字段加索引,也可以对email建立普通索引,还可以建立前缀索引。其建立索引的语句为:

alter table SUser add index index1(email);
alter table SUser add index index2(email(6));

这两种不同建立方式在数据结构和存储上的区别如下:

由于前缀索引只取规定字节数,所以占用空间更小。

但使用前缀索引可能会增加额外的记录扫描次数。比如要执行下面这个查询:

select id,name,email from SUser where email='zhangssxyz@xxx.com'

如果使用普通索引,执行顺序为:

  • 从index1索引树找到满足条件的记录,取得主键为ID2;

  • 在主键索引树上找到对应的行,如果email值正确,将这行记录加入结果集;

  • 从index1索引树上查找下一条记录,发现不满足条件,结束。

由于只回主键索引取一次数据,所以系统认为只扫描一行。

如果使用前缀索引,执行顺序为:

  • 从index2索引树找到满足条件的记录,第一个是ID1;

  • 在主键索引树上找到对应的行,发现email值不正确,丢弃这行记录;

  • 从index2索引树找到满足条件的下一条记录,取得主键为ID2;

  • 在主键索引树上找到对应的行,如果email值正确,将这行记录加入结果集;

  • 重复上述步骤,直到index2上匹配不到正确的前缀。

这个过程需要回主键索引取4次数据,即扫描了4行。

但是,在该场景下,如果定义的index2为email(7),会发现在index2上能直接取到ID2,也就只需要扫描一行。因此,当使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本

那么,你大概就会好奇了,前缀的长度如何确定呢?

在建立索引时,我们需要关注字段的区分度,区分度越高,重复的键值越少。

可以使用下面语句计算列上有多少不同的值:

select count(distinct email) as L from SUser;

然后,可以依次选取不同前缀长度来看:

mysql> 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 SUser;

前缀损失一般会损失区分度,因此在选取长度时心里需要对可以接受的损失比做一个预估,比如想要控制在5%之内,那么L4-L7里需要选取$\ge$95% L的值。

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

前缀索引除了可能增加扫描行数,还有其他影响。比如下面这两个语句:

select id,email from SUser where email='zhangssxyz@xxx.com';

如果使用index1(整个字符串的索引结构),可以利用覆盖索引,在index1查到结果就直接返回,不需要回表;而如果使用前缀索引,就必须回表,即使使用整个字符串的长度email(18),依然需要回表,因为系统不确定前缀索引的定义是否截断了完整信息。

在该例子中,使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是在选择是否使用前缀索引时需要考虑的一个因素。

其他方式

对于邮箱这样的字段,由于用户名差异较大,使用前缀索引的效果可能不错。但有些字段前缀区分度不好,比如身份证号,这时候如果使用前缀索引,可能需要创建长度较长的前缀索引,才能满足区分度要求。但是这也意味着索引占用磁盘空间越大,搜索效率会越低。

假如,能够确定业务需求里只有按照身份证进行等值查询的需求,那么有更好的处理方式,既可以占用更小空间,又能达到相同查询效率:

(1)使用倒序存储

将身份证号倒过来存储,那么可能取6位就有足够的区分度。每次查询时,使用下面的方式:

select field_list from t where id_card = reverse('input_id_card_string');

(2)使用hash字段

可以在表上再创建一个整数字段,比如每次插入新纪录时用crc32()函数得到一个校验码字段。由于校验码可能冲突,在查询时候需要判断id_card字段是否相同。

来看上面两种方法的异同:相同点是都不支持范围查询,不同点有:

  • 占用额外空间不同。倒序存储不消耗额外存储空间,而Hash字段需要增加一个字段。

  • CPU消耗不同。倒序存储方式每次读写都需要额外调用一次reverse函数,而Hash方式需要额外调用一次crc32()函数,从两个函数的计算复杂度看的话前者更小。

  • 查询效率不同。使用Hash方式的查询性能相对更稳定,因为crc32()冲突概率小,可以认为每次查询的平均扫描行数接近1,而倒序存储方式毕竟还是使用前缀索引方式,会增加扫描行数。

MySQL 11 怎么给字符串字段加索引?的更多相关文章

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

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

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

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

  3. MySQL学习(一)日志与索引 --- 2019年1月

    1.MySQL的架构 1).连接器 先根据Ip和端口号,用户名和密码,连接MySQL数据库,连接后如果没有下一步动作,连接就处于空闲状态,此时有一个连接超时时间的设置 wait_timeout默认8小 ...

  4. MySQL中大数据表增加字段,增加索引实现

    MySQL中大数据表增加字段,通过增加索引实现 普通的添加字段sql ALTER TABLE `table_name` ADD COLUMN `num` int(10) NOT NULL DEFAUL ...

  5. MySQL性能优化 - 别再只会说加索引了

    MySQL性能优化 MySQL性能优化我们可以从以下四个维度考虑:硬件升级.系统配置.表结构设计.SQL语句和索引. 从成本上来说:硬件升级>系统配置>表结构设计>SQL语句及索引, ...

  6. mysql中一半会选择什么样的字段为索引?(含索引创建删除查看公式)

    一.数据量庞大的数据做索引 二.该字段经常出现在where的后面,以条件形式存在,经常被用户搜索的字段 三.很少被增删改的字段,因为增删改后,索引会重新排序 索引的创建 create index 索引 ...

  7. 字符串可以这样加索引,你知吗?《死磕MySQL系列 七》

    系列文章 三.MySQL强人"锁"难<死磕MySQL系列 三> 四.S 锁与 X 锁的爱恨情仇<死磕MySQL系列 四> 五.如何选择普通索引和唯一索引&l ...

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

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

  9. 总结: MySQL(基础,字段约束,索引,外键,存储过程,事务)操作语法

    1. 显示数据库列表 show databases; # 查看当前所有数据库 show databases \G   #以行的方式显示 2. 在命令行中,执行sql语句 mysql -e 'show ...

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

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

随机推荐

  1. DotNetGuide 突破了 8K + Star,努力打造C#/.NET/.NET Core全面的学习、工作、面试指南知识库!

    前言 转眼之间维护DotNetGuide(全面的C#/.NET/.NET Core学习.工作.面试指南知识库)已经持续超过了4年多的时间,Commit提交数也超过1400+,在前几天在 GitHub ...

  2. PHP传递参数(跨文件)的8种常见方法

    以下是 PHP 中跨文件传递参数的 8 种常见方法,按场景和安全性分类整理,附详细说明和示例代码: 一.超全局变量(适合请求间数据共享) 1. $_GET / $_POST 用途:通过 URL 或表单 ...

  3. Avalonia跨平台实战(二),Avalonia相比WPF的便利合集(一)

    本话讲的是Avalonia中相比于WPF更方便的一些特性 布局 布局方面没什么好说的,和WPF没什么区别,Grid,StckPanel...这些,不熟悉的话可以B站上找一下教程 xml树 在WPF中我 ...

  4. 关于TCP的握手与挥手

    关于TCP的握手与挥手 前言 由于自己每次都是唱的比懂的好听,光知道唱"三次握手四次挥手",再往里细问SYN标志就只能阿巴阿巴阿巴,为了解决自己的知识储备问题,顺便继续深入了解TC ...

  5. python调用百度ocr接口,实现图片内文字识别

    第一步,到百度智能云申请接口资源 打开地址:https://cloud.baidu.com/?from=console,点击产品下的通用场景文字识别 立即使用,跳转页领取免费资源(土豪可直接购买) 选 ...

  6. 【踩坑系列】使用Comparator.comparing对中文字符串排序结果不对

    1. 踩坑经历 假设有这样一个业务场景,需要对各个城市的订单量排序,排序规则为: 先根据订单量倒序排列,再根据城市名称正序排列. 示例代码: import lombok.Getter; import ...

  7. IIS的垃圾回收对后台任务及隐形后台任务的影响

    IIS的垃圾回收引起的影响 错误排查 现象:在.net core api里创建的BackgroundService定义rabbitmq消费的逻辑,在一段时间运行后经常会出现消费任务中断,在日志里找了很 ...

  8. Oracle 使用UTL_HTTP发送http请求--转载

    参考:https://blog.csdn.net/tmaczt/article/details/82665885 GET方式 CREATE OR REPLACE FUNCTION FN_HTTP_GE ...

  9. 从零开始的PHP原生反序列化漏洞

    1.写在前面 OK 兄弟们,这几天一直在面试,发现很多 HR 喜欢问反序列化相关的内容,今天咱们就从最简单的 PHP 原生反序列化入手,带大家入门反序列化 2.PHP 序列化 在 PHP 中,有反序列 ...

  10. 如何在 Linux 上检查开放的端口并关闭不需要的端口

    检查服务器开放端口并关闭不必要的端口是网络安全管理中的关键环节,开放端口如同服务器的"窗口",若其中存在未被利用或未受保护的端口,就如同为潜在的攻击者敞开了大门,他们可能会利用这些 ...