• 字符串的公共前缀对Mysql B+树查询影响回溯分析


        年前项目组接微信公众号。

    上线之后,跟微信相关的用cid列的查询会话的SQL变慢了几十倍!思考这个问题思考了非常久。从出现以来一直是我心头的一个结。cid这一列是建了索引的,普通的cid列更新都没问题,为何仅仅有微信的有问题?同样的前缀又是怎样影响索引的?


       分析过程
        1.explain下微信cid的查询。微信的cid会以mid-qqwanggou001为前缀插入数据
    explain 
    select *
    from analysis_sessions
    where cid = "mid-qqwanggou001-b99359d9054171901c0"


    分析结果例如以下:


    从explain分析能够看出。这个查询使用了索引,可是innodb觉得有165万行数据须要给mysqlserver筛选(也就是用where条件过滤)。

    假设这些庞大的数据在内存,遍历一遍花不了多少时间。可是极有可能,这些数据是在磁盘上的。这么多的数据从磁盘读取然后加载内存。大量磁盘IO必定是十分的耗时的。

    相比内存的电子运动。磁盘机械臂的物理运动要慢好几个数量级。


    2.分析普通cid的查询

    取数据进行explain。cid = "sid-a2f9047ddf528d837e5f60843c83aae9"。这个数据是不带公共前缀的。

       
    explain 
    select *
    from analysis_sessions
    where cid = "sid-a2f9047ddf528d837e5f60843c83aae9"

    分析结果例如以下:


    同样的列,同样的索引。这次存储引擎向mysqlserver仅仅返回了一行数据。也就是说innodb仅仅须要读取一个二级索引的叶子节点。

    相对于上面那个sql的IO,压力显然小非常多。


    初步分析结论:带有长前缀的cid查询。innodb存储引擎会向mysql上端server返回百万级别的数据。

    这仅仅是现象,我还是想问,同样的表,同样的列,同样的索引结构(B+树索引)。同样的查询,仅仅不同的数据。结果为何有差么大的区别?


    近一步分析
    纠结这个问题非常久了,直到前天晚上散步时候。无意的会想到了 explain结果的key_len这一列。这一列我从来不看,觉得没用。可是27与cid这一列50个varchar的定义格格不入。27明显小于50,首先能够肯定,这个索引用的是前缀索引,说白了,截取了字符串的前面一部分作为索引数据。analysis_session表用的gbk编码。也就是说,索引须要2个字节表示一个varchar。解释一下key_len
        27 = 2 * 12 + 2 + 1
    27位的索引,仅仅索引了前面12个字符中间的2存储长度。后面的一个字节存储Null信息,由于这一列是同意Null的。

    终于结论:问题到这已经非常明了了,微信cid的前缀是17个字符的,大于前缀索引的12个字符,也就是说。全部存储微信cid数据(百万级别)B+树叶子节点将仅仅有一个B+树非叶节点的指针指向这里。于是。当你查微信cid相关的数据时,全部微信cid将被返回给mysqlserver进行where过滤了,效率上讲,这是非常恐怖的。

    索引确实还是被用上了。不然会造成全表扫描。可是这个数据设计的有问题。B+树的查找效率是O(LogN)的,可是遇上这个数据,立马变成O(N),相当于一个局部全表扫描。

        那么合理的猜測。仅仅要有新增的微信cid,微信cid的查询仅仅会变的更慢。

    引申,更佳的代码 practice:
        varchar,blob, text等边长数据建索引的时候。数据库会自己主动建前缀索引,于是B+树不会索引整个字段的部分。非常多同学喜欢用前缀作为字符串的标志,这次要注意了,有前车之鉴了。前缀存入mysql之后会减少检索效率,前缀越长。B+树查询的效率越低。
        这里给出代码的建议:
        1.将前缀作为后缀,startWith改为endWith

        2.不要尝试后缀模糊搜索,like "%.com",这样的做法更糟糕,全然用不了索引,于是全表扫描。




  • 相关阅读:
    名种样式的加入收藏和设为主页代码
    Android蓝牙UUID
    Discuz (1040) notconnect错误的解决办法
    IIS上配置404页面的图文教程
    C#操作excel(多种方法比较)
    Server Application Unavailable出现的原因及解决方案集锦
    怎么在google player下载apk
    apk反编译|android程序反编译
    discuz x2.5帖子无法访问|discuz x2.5 帖子报错500
    C#实现路由器断开连接,更改公网ip
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7326989.html
Copyright © 2020-2023  润新知