比如说,要给邮箱这样的字段加索引,这样长字符串加索引会有什么样的问题?
前缀索引,如果长度长,会浪费大量的空间,同时增加额外的查询成本。
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 索引里面,包含了每个记录的整个字符串。
第二个语句创建的index2 索引里面,对于每个记录都是指取前6个字节。
使用前缀索引,定义好长度,就可以做到节省索引空间,同时不额外增加太多的查询成本。
在建立索引是关注的是区分度,区分度越高越好,意味着重复的键值越少
索引的字符串很大时,创建索引的变得很大,减少索引体积,提升索引扫描速度。
如果 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);
可以使用表上再创建一个整数字段,来保持身份证的校验码,同时在这个字段创建索引。
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';