MySQL中给字符串字段加索引

news/2024/11/20 11:47:57/

文章目录

  • 前言
  • 一、前缀索引和普通索引
  • 二、前缀索引对覆盖索引的影响
  • 三、优化前缀索引


前言

学完了MySQL索引部分,我们清楚的认识到给子段添加索引可以快速的进行查询,节约时间。但是索引有很多。那么对于字段怎么加索引,加什么索引。加到索引不同,效率肯定也会有不同的。接下来,我们研究下,怎么给字符串字段加索引


一、前缀索引和普通索引

我们依旧是通过一个例子进行讲解。

我们用邮箱登录这个业务。创建了一个用户表,SQL句如下:

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

要是有邮箱登录,业务代码中一定会出现如下这样的SQL语句:

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

对于这查询语句,相比加上索引效率效率更高。
但是加上什么索引呢?
如果只是普通的加上索引,那么相应的索引对应的B+树中存储的就这email索引列的全部内容。想必都知道,一个邮箱账号包含的字符串是很长。如果把这一个很长的字符串充当索引,那是很浪费存储空间的。为此,我们可以使用前面提到过前缀索引,即把email的一部分字符串设置为索引。接下来,我们分析学习下两者的效率。

针对email字段创建如下两个不同的索引,进行分析:

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

第一个语句创建的index1索引里面,包含了每个记录的整个字符串;而第二个语句创建的index2
索引里面,对于每个记录都是只取前6个字节。

针对这两个的存储,存储结构图,如下所示:
对index1:
在这里插入图片描述
对index2:
在这里插入图片描述
从图中的存储可以看出,email(6)这个存储占用的空间更小。这是使用前缀索引的优势,但是查询效率上呢,接下来我们分析一下。

执行下面的SQL语句,看看不同的索引执行流程有何不同:

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

如果使用的是index1(即email整个字符串的索引结构),执行顺序是这样的:

  • 从index1索引树找到满足索引值的这条记录,取得ID2的值;
  • 到主键上查到主键值是ID2的行,判断email的值是正确的,将这行记录加入结果集;
  • 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足条件了,循环结束。

这个过程中,只需要回主键索引取一次数据,所以系统认为只扫描了一行。

如果使用的是index2 (即email(6)索引结构),执行顺序是这样的:

  • 从index2索引树找到满足索引值是’zhangs’的记录,找到的第一个是ID1;
  • 到主键上查到主键值是ID1的行,判断出email的值不是这行记录丢弃;
  • 取index2上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出ID2,再到ID索引上取整行然后判断,这次值对了,将这行记录加入结果集;
  • 重复上一步,直到在idxe2上取到的值不是’zhangs’时,循环结束。

通过这个对比,你很容易就可以发现,使用前缀索引后,可能会导致查询语句读数据的次数变多。

通过看使用前缀索引结构,进行检索。如果设置的前缀个数较少,那各个字段的区分度不大,就会有很多重合的索引,就需要多次回表进行检查。区分度越高越好。因为区分度越高,意味着重复的键值越少。但是要存储的字符串就会越多,所以要平衡下,找到最好的前缀索引。

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

我们将上面的SQL查询语句,变成下面的:

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

如果使用index1(即email整个字符串的索引结构)的话,可以利用覆盖索引,从index1查
到结果后直接就返回了,不需要回到ID索引再去查一次。而如果使用index2(即email(6)索引结
构)的话,就不得不回到ID索引再去判断email字段的值。

将index2的定义修改为email(18)的前缀索引,这时候虽然index2已经包含了所有的信息,但InnoDB还是要回到id索引再查一下,因为系统并不确定前缀索引的定义是否截断了完整信

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

对前缀索引方式的优化

三、优化前缀索引

对于邮箱这样的使用前缀比较合适,但是如果像身份证这样的,因为身份证前很多位都是表示地理信息的,所以每个人的区分度不大。

为了解决这个区分度的问题,设计了如下两种方法:

第一种方式:倒序存储
存储身份证号的时候把它倒过来存,每次查询的时候,可以这么写:

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

第二种方式:使用hash字段
在表上再创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引:

alter table t add id_card_crc int unsigned, add index(id_card_crc);

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

它们这两个都不支持范围查询。倒序存储的字段上创建的索引是按照倒序字符串的方式排序的,已经没有办法利用索引方式查出身份证号码在[ID_X, ID_Y]的所有市民了。同样
地,hash字段的方式也只能支持等值查询

键值越少。


http://www.ppmy.cn/news/12541.html

相关文章

【MySQL进阶教程】MySQL管理

前言 本文为 【MySQL进阶教程】MySQL管理 相关知识,下边将对系统数据库,常用工具(包括:mysql、mysqladmin、mysqlbinlog、mysqlshow、mysqldump、mysqlimport/source)等进行详尽介绍~ 📌博主主页&#xff…

有了独自开,我们离自己开发一套系统还会远吗

前言: 大家好,我是小威,今天给大家分享一个开发平台。能够独自开发一套系统,这想必对开发者是一个福音。下面就为大家介绍一下这个平台,来帮助我们开发自己的系统。 文章目录简单介绍优点优秀案例平台福利总结简单介绍…

【nvidia CUDA 高级编程】NVSHMEM 直方图——分布式方法

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…

设计模式简要汇总

一、面向对象设计原则 开闭原则:一个软件实体(类、模块、函数)应该对扩展开放,对修改关闭。依赖倒置原则:高层模块不应该依赖底层模块,它们都应该依赖于抽象。抽象不应该依赖于细节,细节应该依…

Django搭建个人博客Blog-Day05

创建文章模块创建文章app在虚拟环境中,apps路径下使用如下代码:# 进入虚拟环境 workon wsl # 进入要创建app的路径下 cd blog/blog/apps # 创建app python ../../manage.py startapp articles将articles注册进配置文件dev.py中的INSTALLED_APPSINSTALLED…

make_blobs函数

示例1: # make_blobs示例 from sklearn.datasets.samples_generator import make_blobsX, y make_blobs(n_samples10, centers3, n_features2,random_state0) #看看数据集长什么样 plt.scatter(X[:, 0], X[:, 1], cy, cmap"rainbow");示例2:…

Linux chattr命令

Linux chattr命令Linux 命令大全Linux chattr命令用于改变文件属性。这项指令可改变存放在ext2文件系统上的文件或目录属性,这些属性共有以下8种模式:a:让文件或目录仅供附加用途。b:不更新文件或目录的最后存取时间。c&#xff1…

监控需求以及开源方案的对比

文章目录监控需求以及开源方案的对比监控需求来源可观测性三大支柱指标监控日志链路追踪业界方案横评ZabbixZabbix优点Zabbix缺点Open-FalconOpen-Falcon 的优点Open-Falcon 的缺点PrometheusPrometheus 的优点Prometheus 的缺点NightingaleNightingale 的优点Nightingale 的缺…