美文网首页
11.长字符串的索引

11.长字符串的索引

作者: 胖达_4b7e | 来源:发表于2019-02-14 00:01 被阅读0次

    根据email查用户
    email整个索引
    alter table SUser add index index1(email);


    这样占太多空间了

    前缀索引好

    alter table SUser add index index2(email(6));

    这样空间小
    但是, 如果区分度不高, 很多前缀一样的 就要很多次回表

    选择合适的前缀长度

    select 
      count(distinct left(email,4))as L4,
      count(distinct left(email,5))as L5,
      count(distinct left(email,6))as L6,
      count(distinct left(email,7))as L7,
    from SUser;
    

    找出不小于 L * 95% 的值,假设这里 L6、L7 都满足,你就可以选择前缀长度为 6。

    前缀索引 坏处: 增加扫描行数

    如果使用的是 index1(email 整个字符串的索引结构),执行顺序:
    1.从 index1 索引树找到满足索引值是’zhangssxyz@xxx.com’的这条记录,取得 ID2 的值;
    2.到主键上查到主键值是 ID2 的行,将这行记录加入结果集;
    3,取 index1 索引树上刚刚查到的位置的下一条记录,发现已经不满足 email='zhangssxyz@xxx.com’的条件了,循环结束。

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

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

    1.从 index2 索引树找到满足索引值是’zhangs’的记录,找到的第一个是 ID1;
    2.到主键上查到主键值是 ID1 的行,判断出 email 的值不是’zhangssxyz@xxx.com’,这行记录丢弃;
    3.取 index2 上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出 ID2,再到 ID 索引上取整行然后判断,这次值对了,将这行记录加入结果集;

    重复上一步,直到在 idxe2 上取到的值不是’zhangs’时,循环结束。

    index2 不是 email(6) 而是 email(7),也就是说取 email 字段的前 7 个字节来构建索引的话,即满足前缀’zhangss’的记录只有一个,也能够直接查到 ID2,只扫描一行就结束了。

    也就是说使用前缀索引,要定义好长度

    如果 查询语句是
    select id,email from SUser where email='zhangssxyz@xxx.com';
    不用名字, 只要id 和email
    整个字符串索引 就可以 覆盖索引, 不用回表
    但是 前缀索引 必须回到 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);
    查询时 hash+原字符串
    select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
    crc32 算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近 1
    更新的时候用触发器就行了

    相关文章

      网友评论

          本文标题:11.长字符串的索引

          本文链接:https://www.haomeiwen.com/subject/nvajeqtx.html