上一节介绍了BTree的本质,本节我们回到最开始,介绍一次查询都经过哪些步骤。 本节会结合源码粗略介绍查找过程(源码既枯燥又无味。。)
几个问题:
sql怎么解析,解析成什么了?
是否有缓存?怎么查缓存的?
举例:
create table t1 (
`id` int AUTO_INCREMENT;
`a` varchar(255),
`b` varchar(255),
`c` int
primary key (`id`),
key `idx_a_b_c` (`a`,`b`,`c`)
) ENGINE=InnoDB;
select * from t1 where a = "x";
先自问: 如果让你实现这个功能 你会怎么做呢?
Client发送二进制数据给Server ---> 一个通信协议来编码数据包
Server解析数据包后 生成一个字符串 select * from t1 where a = "x"
翻译字符串成为程序可执行的语言 "select * from t1 where a = "x"" -> THD 数据结构 --> 词法语法分析器负责完成这个工作
依据TableName 同时发现满足idx_a_b_c条件 找到idx_a_b_c索引的数据结构 ---> 索引查找
BTree查找算法 找到 a =x 返回id 再回表查聚簇索引 得到一堆二进制数据
根据通信协议传给Client 解析后 显示在屏幕上
其实基本原理就是这样! Mysql只是在这个基础流程上做了很多“优化” 保证在商业用途中的可靠性 稳定性和扩展性!
下面介绍Mysql核心流程
1.MysqlClient依据Mysql通信协议 发送数据到Server 特别类似直播用的MQTT协议
官方文档: https://dev.mysql.com/doc/internals/en/client-server-protocol.html
中文:https://blog.51cto.com/boytnt/1275952
2.解析数据包 (mysql_parse sql_parse.cc)生成AST数据结构(TODO:后面举例)
2.1 语法解析器 (THD::sql_parser())
用Bison 一个开源分析器; 其实就是调用一个一个词法分析函数 把字符串序列转为一个对象!
2.2 词法分析器 (yylex())
每个单词对应对象哪个属性 比如 "select" 翻译过来就是本次query类型为SELECT
(语法词法分析 后续专门出一节讲,说白了自己都能写 简单点就是一堆if else 判断某个字符串该执行什么命令 只不过分析器把这些规则化 文本化了)
3.执行SQL命令 mysql_execute_command(thd)
3.1 SELECT类型 执行 do_select()
3.2 进入存储引擎层面进行索引查找 ha_innobase::index_first()
3.3 查找行 可能使用mvcc row_search_mvcc()(MVCC实现后续介绍)
3.4 先查缓存
3.4.1 如果判断是一个连续性查找 从Cache里获取 ha_get_record_buffer()
“当前数据的下一个数据 大概率被查到” 一次查询后 mysql会多查一些数据放到进程级别cache里
(这里留个疑问: 怎么查来着? where id < 3 是一次btree查找吗?? 那连续性缓存有啥用?)
3.4.2 Cache没有 尝试自适应hash索引
BTree是lg(N)级别的复杂度,Mysql在此上做了一层hash索引(后续搞一个专题),其实就是一个index[key],key: 是查询字段+where条件 value:row的内容
自适应的意思是 Cache不可能把所有数据都缓存下来,其实也是类似LRU原理,某个page页访问量达到一定阈值会将数据存入Cache
3.5 BTree查找
一次lg(N)级别的查找 找到page 然后顺序查到record,并返回数据,至此一次查询结束
4.后续
还有一个重要概念没有提到 事务隔离级别 如何保证可见性? 后续再锁的文章里再做介绍