登录 |  注册
首页 >  数据库 · 存储 >  MySql实战精选笔记 >  怎么给字符串字段加索引?

怎么给字符串字段加索引?

比如说,要给邮箱这样的字段加索引,这样长字符串加索引会有什么样的问题?

前缀索引,如果长度长,会浪费大量的空间,同时增加额外的查询成本。

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

如果使用邮箱登录,这样会出现这样的语句:

select f1 ,f2 from Suser Where emial='xxx';

如果 email 不建索引,那么就只能全表扫描,如果 email 这个字段是哪个没有索引,那么这个语句只能做全表扫描。

MySQL 支持前缀索引,可以定义字符串的一部分作为索引,创建索引的语句不指定前缀长度,那么索引就会包含整个字符串。

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

第一个语句创建的 index1 索引里面,包含了每个记录的整个字符串。

index.png

第二个语句创建的index2 索引里面,对于每个记录都是指取前6个字节。

index2.png

使用前缀索引,定义好长度,就可以做到节省索引空间,同时不额外增加太多的查询成本。

当要给字符串创建前缀索引时,如何确定使用多长的前缀?

在建立索引是关注的是区分度,区分度越高越好,意味着重复的键值越少

前缀索引

索引的字符串很大时,创建索引的变得很大,减少索引体积,提升索引扫描速度。

如果 index1 的话,可以利用覆盖索引,从

覆盖索引

所谓的覆盖索引,是可以通过索引直接获取行的数据,不需要再去读取数据行,也就是叶子节点已经包含查询的数据,避免回表查询。

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

前缀索引可能会增加扫描行数,这样会影响性能,前缀索引。

select id,name,email from SUser where email='aaa@www.com'

如果 index1 的话,可以利用覆盖索引,从 index1 直接返回即可,不需要回到 id 索引再去查一次,如果使用 index2 即 email(6) 索引再去判断 email 字段的值。

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

使用前缀索引用户数覆盖索引的查询性能优化。

还有没有其他方式帮助字符串建立索引

比如能够给确定业务需求里面只有按照身份证等值查询的需求,需要给身份证加索引,有没有什么办法,占用更小空间,也能达到相同的查询效率。

第一种方式是使用倒序存储

身份证最后 6 位,没有重复逻辑,因此最后 6 位可能提供了足够的区分度。

先倒序存储,然后再创建前缀索引。

如果存储身份证的时候倒过来存,每次查询的时候,可以这样:

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 的值是精确相同的。

select field_list from t where id_card crc=crc32('input id card string') and id card='input_id_card_string';

对比

从占用的额外的空间来看,倒序存储方式在主键上,不会消耗额外的存储空间,hash 字段需要增加字段。

CPU 消耗方面,倒序每次写和读的时候,需要额外一个 reverse 函数,而 hash 字段的方式需要额外调用一次 crc32() 函数。reverse 函数额外消耗的 CPU 资源会更小些。

从查询效率上,使用 hash 字段方式的查询性能更加稳定一些, crc32 算出来的值虽然有冲突概率,但是概率非常小。

总结

直接创建完整索引,这样占用很大空间

创建前缀索引,节省空间,但是会增加扫描次数,并且不能使用覆盖索引。

倒序存储,再创建前缀索引,用于解决字符串本身前缀区分度不够的问题,不支持范围扫描。

创建 hash 字段索引,查询性能稳定,有额外的存储和计算消耗,不支持范围扫描。

上一篇: 使用索引的场景及注意事项:不走索引的原因
下一篇: 为什么有的时候SQL执行很慢“抖一下”
推荐文章
  • mysql只支持一种join算法:Nested-LoopJoin(嵌套循环连接),但Nested-LoopJoin有三种变种:SimpleNested-LoopJoin,IndexNested-LoopJoin,BlockNested-LoopJoin(简单-索引-缓冲区)原理:1.SimpleNe
  • redis是一个内存数据库,一旦断电或服务器进程退出,内存数据库中的数据将全部丢失,所以需要redis持久化 redis持久化就是把数据保存在磁盘上,利用永久性存储介质将数据保存,在特定的时间将保存的数据进行恢复的工作机制redis提供两种持久化机制RDB:存储数据结果,关注点在数据AOF:存储操作
  • 通过SQL的执行过程来介绍MySQL的基础结构.     首先有一个user_info表,表里有一个id字段,执行下面这条查询语句:Select * form user_info where i
  • 索引(Index)是帮助MySQL高效获取数据的数据结构,索引的目的在于提高查询效率,就像字典和书籍的目录一样,有了目录,可以帮助你快速查找你需要的内容。可以理解为一个排好序的快速查找数据结构。也就是
  • 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什么要有四个隔离级别。今天我们就先来聊聊MySQL中事务的隔离性的实现原理,后续还会继续出文章分析其他特性的
  • 前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。相信你还记得,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。那么,一条更新语句
学习大纲