阿里百度华为如何使用MySQL给字符串加索引(下)

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


看如下SQL:

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

与前例SQL语句:

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

相比,该语句只要求返回id和email。


若使用index1,可利用覆盖索引,从index1查到结果后直接返回,不需回到ID索引再查一次。

而若使用index2(email(6)),得回ID索引再判断email字段值。


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

即前缀索引根本用不上覆盖索引对查询的优化,这也是选择是否使用前缀索引时需要考虑的因素。


3 其他方案


对类似邮箱这样字段,前缀索引可能还行。但遇到前缀区分度不好的,怎么办?


比如身份证号18位,前6位是地址码,所以同县人身份证号前6位一般相同。

假设维护数据库是个市公民信息系统,若对身份证号做长度6前缀索引,区分度非常低。

可能需创建长度12以上前缀索引,才能够满足区分度要求。


索引选取越长,占磁盘空间越大,相同数据页能放下索引值越少,查询效率就越低。


  • 若能确定业务需求只有按身份证进行等值查询的需求,还有没有别的处理方法,既可占用更小空间,也能达到相同查询效率?
    Yes!


第一种方式使用


3.1 倒序存储

如果存储身份证号时把它倒过来存,每次查询这么写:

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

由于身份证号最后6位没有地址码这样重复逻辑,所以最后6位可能提供足够的区分度。

实践中也别忘记使用count(distinct)验证区分度哦!


第二种方式是使用


3.2 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'

这索引长度变4字节,比原来小很多。


3.3 倒序存储和使用hash字段异同点

相同点


都不支持范围查询。

  • 倒序存储的字段上创建的索引
    按倒序字符串的方式排序,已无法利用索引查出身份证号码在[ID_X, ID_Y]的所有市民
  • hash字段也只支持等值查询

阿里百度华为如何使用MySQL给字符串加索引(下)


阿里百度华为如何使用MySQL给字符串加索引(下)

上一篇:oracle之 变更OS时间对数据库的影响


下一篇:使用Swashbuckle.AspNetCore生成.NetCore WEBAPI的接口文档