给字符串字段加索引

149 阅读3分钟

这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

某些情况下,希望直接通过某字段作为条件进行查询。如果该字段没有索引,则该语句只能做全表扫描。 那么如何给该字符串字段添加索引呢?

给字符串字段添加索引的方法

  1. 前缀索引 - 定义字符串的一部分作为索引 - 若创建索引的语句不指定前缀长度 - 索引会包含整个字符串
    EG:1. alter table SUser add index index1(email);
    2. alter table SUser add index index2(email(6));
    1. 前缀索引的优劣
      1. 占用的空间更小
      2. 可能会增加额外的记录扫描次数
    2. 具体流程 - select id, name, email from SUser where email='zhangssxyz@xxx.com';
      1. index1[email整个字符串的索引结构]
        1. index1索引树找到满足索引值'zhangssxyz@xxx.com'的这条记录,取得ID的值;
        2. 主键上查到主键值是ID的行,判断email的值是正确的,将这行记录加入结果集;
        3. 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足email='XX'的条件,循环结束;
          只需要回主键索引取一次数据,系统认为只扫描了一行。
      2. index[email(6)索引结构]
        1. index2索引树找到满足索引值是'zhangs'的记录,找到的第一个是ID1;
        2. 到主键上查找到主键值是ID1的行,判断email的值不是'zhangssxyz@xxx.com', 这行记录丢弃;
        3. 取index2上刚刚查到的位置的下一条记录,发现仍然是'zhangs',取出ID2;
        4. 再到ID索引上取整行然后判断,值对,将这行记录加入结果集;
        5. 重复第3-4步,知道index2索引树上取到的值不是'zhangs'时,循环结束;
          要回主键索引取4次数据 - 扫描了4行
          使用前缀索引,可能会导致查询语句读数据的次数变多 使用前缀索引,定义好长度,可以节省空间+不额外增加太多的查询成本

    如何确定使用多长的前缀?

      建立索引时关注的是区分度 - 区分度越高越好 - 重复的键值越少   
      通过统计索引上有多少个不同的值来判断要使用多长的前缀  
      预先设定可接受的损失比例 - 找出不小于L*95%的值  
    
    3. 前缀索引对覆盖索引的影响
    使用前缀索引无法使用覆盖索引对查询性能的优化 - 系统并不确定前缀索引的定义是否截断了完整信息,还是会回到主键上查询
  2. 其他方式 - 前缀的区分度不好时
    1. 倒序存储 - 例如身份证后6位有足够的区分度,前面的没有
    2. hash字段 - 表上再创建一个整数字段 - 保存身份证的校验码,在这个字段上创建索引
    3. 倒序存储和hash字段的异同:
      1. 都不支持范围查询
        1. 倒序了怎么按原序范围查
        2. hash - 等值查询
各类倒序存储hash字段
占用的额外空间主键索引上,不消耗需增加一个字段,倒序存储的前缀长度稍长,消耗基本差不多
CPU消耗每次读、写 - 额外调用一次reverse函数hash 额外调用crc32()函数 - 计算复杂度来看,reverse函数额外消耗的CPU资源会更小
查询效率前缀索引 - 增加扫描行数查询性能相对更稳定,crc32算出来有冲突的值概率很小。平均行数接近1