MySQL实现的一点总结(四)

So,数据页(页类型INDEX)就是B+树上的节点,他们是属于某个段的(INODE Entry记录着32个碎片页和三个区链表),在索引树根页面的page header中会包含一个segment header(内有PAGE_BTR_SEG_LEAF和PAGE_BTR_SEG_TOP表示本索引包含的叶节点段和非叶节点段的INODE Entry的位置),把索引树和对应的段联系起来

系统表空间:0、1、2页同样是FSP_HDR、IBUF_BITMAP和INODE,3~7页特殊:
3:页类型SYS,change buffer header;
4:页类型INDEX,change buffer root;
5:页类型TRX_SYS,transaction system;
6:SYS,first rollback segment;
7:SYS,data dictionary header;
先看很重要的第7页,MySQL有一些内部系统表(数据字典),比如我们执行一般语句时,会根据表名到SYS_TABLE表中获取TABLE_ID,然后根据TABLE_ID到SYS_COLUMNS表中获取列信息,同时到SYS_INDEXS表中获取索引信息(INDEX_ID以及对应的B+树根页面位置),然后根据INDEX_ID到SYS_FIELDS表中获取索引列信息——这4个表是整个数据库的表中之表,他们的元数据硬编码到代码中,并用第7页记录他们的B+树根页号
另外页7还记录InnoDB的一些全局属性,如MaxRowID、MaxTableID、MaxIndexID、MaxSpaceID等
Information_schema表:根据系统表建立的仿品,供用户参考

猜测流程:
查询——>系统表空间(第七页)——>系统表(sys_table)——>根据表名获取table_id——>获取index_id以及对应的根页号——>到达索引B+树根页面——>在树中查找(页内通过slot和单链定位,通过对应的页号到达下一层,同层的页面间形成双链)——>到达叶节点获得记录或者拿到主键后回表
如果是增删改的话可能会涉及页面增减,则应该要通过B+树根页面的segment header找到对应的INODE Entry,由段来申请页面并记录(碎片页数组和三个完整区链表)
插入——>根据表名在系统表中拿到table_id——>获取index_id以及对应的根页号——>到达根页面——>B+树查询找到位置——>if页面有空间则直接插,无空间or造成分裂则申请新的页面——>获取根页面page header中本索引的两个段(叶节点段和非叶节点段)信息(INODE Entry的位置)——>到INODE页中获取对应的Entry(包含本段使用的碎片页号和三个区链表基节点)——>if碎片页不满32个——>去表空间的free_frag链头(区)拿页面(free_frag用完挂到full_frag链,从free拿节点(区)到free_frag),页号记录到INODE Entry;if 32个碎片页用完了——>开始使用完整的区(64个连续的页面),从INODE Entry的free区链拿区到not_full区链,not_full中用完的区挂到full区链

单表访问:
不同类型的查询对应定义不同的访问方法:
Const:主键or非空唯一二级索引的等值比较,如where id = 134;(单值,常数级)
Ref:普通二级索引的等值比较,如where k1 = a;(is单点扫描区间)
Ref_or_null:对比ref多扫描了一个null区间,如where k1 = a or k1 = null;(null值记录在索引的最左边)
Range:需要扫描若干单点区间or范围区间,如where k1 in (a,b,c) or k2 > 999;
Index:可从二级索引中全表扫描获取结果而无需回表,如select k_part1,k_part3 from table where k_part2 = a;(可在联合索引中直接获得结果而无需回表)
All:全表扫描

索引合并:(一般情况下,获取每条二级索引后都要立即回表,有时可优化,如:)

  1. intersection(取交集):where k1 = a and k2 = b;当两结果id相同时才回表,减少了消耗,此时要求二级索引中的结果是按id有序的——>then,k1和k2索引中各取一条,比较id,小的丢弃,大的进行下次比较,相等则可以回表(可看出此方法要求有序)
  2. union(取并集):where k1 = a or k2 = b;同样要求二级索引中按主键有序,but MySQL也做了sort_union,对于主键无序的,先排序再union——but并没有实现sort_intersection

连接:(两表做笛卡尔积,产生m * n条记录)
过程:选择一张驱动表——>分析只涉及本表的条件,选择最佳单表访问方法——>产生驱动表结果集——>对结果集中的每一条记录(此时关于驱动表的条件已经变成了定值),到被驱动表中,根据只涉及被驱动表的条件,选择最佳单表访问方法——>最终结果集
注意:驱动表每获得一条结果,就到被驱动表中匹配
举例:where t1.m1 > 1 and t1.m1 = t2.m2 and t2.n2 < a;

  1. 选t1为驱动表,根据m1 > 1选择最佳访问方法(比如range或index),得到驱动表结果集(比如有m1 = 2,m1 = 3);
  2. 当得到m1 = 2时,被驱动表的条件就变成了m2 = 2 and n2 < a,选择最佳访问方法,得到结果集1
  3. 同理m1 = 3时得到结果集2
  4. 合并得到最终结果
    由此可知,连接is嵌套循环,连几个表就嵌套几层,so,为加快速度:1.使用索引;2.开辟缓存装驱动表的结果集,然后一次性与被驱动表匹配,以减少被驱动表的I/O(join buffer只存查询列表及与条件相关的列——so,不使用select *可以增加buffer存储记录的数量)

以上为内连接(inner join),只留下符合where条件的记录,
对于外连接(outer join),可以同时留下不符合on条件的驱动表项
Ex:t1 left join t2:t1是驱动表,被留下;
T1 right join t2:t2是驱动表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值