字符串的公共前缀对Mysql B+树查询影响回溯分析
上线之后,跟微信相关的用cid列的查询会话的SQL变慢了几十倍!思考这个问题思考了非常久。从出现以来一直是我心头的一个结。cid这一列是建了索引的,普通的cid列更新都没问题,为何仅仅有微信的有问题?同样的前缀又是怎样影响索引的?
explain
select *
from analysis_sessions
where cid = "mid-qqwanggou001-b99359d9054171901c0"
分析结果例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" width="867" height="100" />
从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",这样的做法更糟糕,全然用不了索引,于是全表扫描。
字符串的公共前缀对Mysql B+树查询影响回溯分析的更多相关文章
- MySQL知识树-查询语句
在日常的web应用开发过程中,一般会涉及到数据库方面的操作,其中查询又是占绝大部分的.我们不仅要会写查询,最好能系统的学习下与查询相关的知识点,这篇随笔我们就来一起看看MySQL查询知识相关的树是什么 ...
- LeetCode 14. Longest Common Prefix字典树 trie树 学习之 公共前缀字符串
所有字符串的公共前缀最长字符串 特点:(1)公共所有字符串前缀 (好像跟没说一样...) (2)在字典树中特点:任意从根节点触发遇见第一个分支为止的字符集合即为目标串 参考问题:https://lee ...
- leetcode_最长公共前缀
题目:Write a function to find the longest common prefix string amongst an array of strings. 题解:给出的函数为: ...
- LeetCode 7最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- [LeetCode]14. Longest Common Prefix最长公共前缀
Write a function to find the longest common prefix string amongst an array of strings. If there is n ...
- LeetCode刷题-最长公共前缀(简单)
题目描述 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow ...
- 最长公共前缀 leetcode 14
方法一(纵向扫描) 解题思路 先计算出数组中最小的字符串长度,这样就避免了越界的情况,思路更加明确,但同时时间复杂度就相应的上升了. 先计算所有字符串在同一列上的字符是否相同,然后依次向后延伸. 代码 ...
- 每日一道 LeetCode (5):最长公共前缀
前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee: https://gitee.com ...
- Leetcode13. 罗马数字转整数Leetcode14. 最长公共前缀Leetcode15. 三数之和Leetcode16. 最接近的三数之和Leetcode17. 电话号码的字母组合
> 简洁易懂讲清原理,讲不清你来打我~ 输入字符串,输出对应整数  E. Vanya and Field 思维题
E. Vanya and Field time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- android 从零单排 第一期 按键显示helloworld
啦啦啦- 我是qscqesze 今天开始android的从零单排啦啦啦- 首先从最简单的开始 要求: 程序运行后,单击屏幕上的按键后可以显示一句话,如“Hello World!” 这是一个最基础最基础 ...
- Asky极简教程:零基础1小时学编程,已更新前8节
Asky极简架构 开源Asky极简架构.超轻量级.高并发.水平扩展.微服务架构 <Asky极简教程:零基础1小时学编程>开源教程 零基础入门,从零开始全程演示,如何开发一个大型互联网系统, ...
- Oracle | 给表和字段添加注释
comment on column 表名.字段名 is '注释内容'; comment on column OPERATOR_INFO.MAIN_OPER_ID is '归属操作员'; c ...
- 3.3V与5V电平双向转换
http://www.amobbs.com/thread-5541344-1-2.html 3.3V转5V:S3输入为0V时,NMOS管导通,S5=S3=0V:S3输入为3.3V时,NMOS管截止,S ...
- XStream转换Java对象与XML
1.引入需要的jar包,在pom.xml中配置依赖 <dependency> <groupId>com.thoughtworks.xstream</groupId> ...
- [c#]WebClient异步下载文件并显示进度
摘要 在项目开发中经常会用到下载文件,这里使用winform实现了一个带进度条的例子. 一个例子 using System; using System.Collections.Generic; usi ...
- js判断手机端和pc端
var browser = { versions: function() { var u = navigator.userAgent, app = navigator.appVersion; retu ...
- 【Nginx】ngx_event_core_module模块
ngx_event_core_module模块属于事件模块,它是其他事件类模块的基础.它主要完毕下面任务: 创建连接池 决定使用哪些事件驱动机制 初始化将要使用的事件模块 以下分析该模块的代码. ng ...
- 使用Bootstrap 3开发响应式网站实践07,页脚
页脚部分比较简单,把一个12列的Grid切分. <footer> <div class="container"> <div class="r ...