• 21 mysql ref 查询


    前言

    这里主要是 探究一下 explain $sql 中各个 type 

    诸如 const, ref, range, index, all 的查询的影响, 以及一个初步的效率的判断 

    这里会调试源码来看一下 各个类型的查询 需要 lookUp 的记录 

    以及 相关的差异 

    此系列文章建议从 mysql const 查询 开始看

     

    测试表结构信息如下 

    1. CREATE TABLE `tz_test` (
    2. `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    3. `field1` varchar(12) DEFAULT NULL,
    4. PRIMARY KEY (`id`) USING BTREE
    5. ) ENGINE=InnoDB AUTO_INCREMENT=3333343 DEFAULT CHARSET=utf8

     

    测试数据为序列 1 – 99

    6435438d244443e8ab24c52f9a11fee7.png

     

     

    ref 查询存在的记录

    更新表结构, 增加 field1 的索引配置 

    1. CREATE TABLE `tz_test` (
    2. `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    3. `field1` varchar(12) DEFAULT NULL,
    4. PRIMARY KEY (`id`) USING BTREE,
    5. KEY `field1` (`field1`) USING BTREE
    6. ) ENGINE=InnoDB AUTO_INCREMENT=3333343 DEFAULT CHARSET=utf8

     

    执行更新, 更新一部分记录的 field1 为 ”field33”

    update tz_test set field1 = 'field33' where id in (33, 35, 60);

     

    mysql 读取索引, 这个是在读取索引的数据, 然后和 查询条件进行对比  

    索引记录存放了 原字段的值 -> 记录的主键 

    这里获取到第一个匹配的索引记录

    62d1768279794aa2a03c5c0da1cdd86f.png

     

    up_rec 索引记录信息如下, 为 ‘field33’ -> 33

    然后这里将 pcur->btr_cur->page_cur.rec 更新为 ‘field33’ -> 33 对应的索引的位置 

    然后 接下来就是 读取索引的记录

    d069245bba2943479f258703fc54b853.png

     

    然后是比较 索引字段的信息 和 查询条件, 如果匹配上 才获取对应的记录

    89208e1f1d354a4fa4b3a9c595407cdf.png 

     

    是否需要查询真实记录?

     

    这里会有两种情况, 一种情况是查询的 索引字段 以及 主键, 不需要额外的查询真实记录, 术语称之为 覆盖索引 

    假设是普通字段, 这里更新 need_to_access_clustered 为 TRUE

    b8db21b9b4b14b02a3ab8045ff801b6a.png

     

    另外一种是需要根据 主键关联查询 到 真实的记录, 术语称之为 回表 

    修改数据表结构如下 

    1. CREATE TABLE `tz_test` (
    2. `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    3. `field1` varchar(12) DEFAULT NULL,
    4. `field2` varchar(16) DEFAULT NULL,
    5. PRIMARY KEY (`id`) USING BTREE,
    6. KEY `field1` (`field1`) USING BTREE
    7. ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8
    8. update tz_test set field2 = id;

     

    row_sel_get_clust_rec_for_mysql 中是根据索引记录获取真实的记录 

    prebuilt->clust_ref 为根据索引记录构造出的 主键查询条件

    btr_pcur_open_with_no_init 根据这个主键查询条件去定位目标记录, 将记录信息更新到 prebuilt->cluster_pcur 中相关 

    a5a1d87d06b74461a408ba00ebf794e0.png

      

    根据索引记录 构造 主键查询条件的地方, 比如这里 ‘field33’ -> 35 的索引记录 

    构造出来的主键查询条件为 “where id = 35”

    246426680b8046e4b44f633fadeea46a.png

     

    更新待复制 rec 为 cluster_rec, 这里的 cluter_rec 为真实记录的地址信息

    f635f964c1aa45259efbfbe1e1ccbf52.png 

    cluster_rec 的记录信息如下 

    58835178ec7847bb83ade74c17244cc5.png 

    读取到了真实记录的信息到 mysql_buf

    47d70afa718c42528f8e6b2ccba5675d.png 

    然后不断向下迭代索引记录, 这里是迭代到了 ‘field33’ -> 35

    依次会迭代 ‘field33 -> 60’, ‘field34’ -> 34

    到 ‘field34’ -> 34 的时候, 比较索引条件 跳出了 row_search_mvcc 的循环 

    8db8471f02ec4e56b424e5ca662752fe.png

     

    这里遍历的索引记录信息依次如下, 索引是按照顺序排列的 

    到 ‘field34’ -> 34 的时候, 比较索引条件 跳出了 row_search_mvcc 的循环 

    7f233b6c303149ee97f64ee3275f2ac7.png

     

    第二条以及之后的记录是缓存在了 prebuilt->fetch_cache 中, 最多预取 7 条记录 

    10a0127e77914022b9d4ca59ac3219c9.png

     

    第二次, 第三次获取数据是直接通过缓存获取 

    这里 prebuilt->fetch_cache 中各个元素是已经转换好了的 mysql_rec, 因此 这里是直接 memcpy 到 READ_RECORD.record 中即可 

    56817e97743b4876804cb7742693cbf1.png

     

     

    ref 查询不存在的记录

    比如说我这里执行一个查询 “select * from tz_test where field1 = 'field133';”

    然后时 查询不到记录的, 这里来调试一下 这里的整个流程

    查询索引, 定位到的最近的一条记录是索引记录 ‘field14 -> 14’, 然后是根据是根据条件进行匹配, 结果匹配不上退出 row_search_mvcc

    ec70f69a19224417afc531d8190e385a.png

     

    索引条件匹配不上之后退出  

    83d0e35ee98e4a07965b3f6fa2b17d4e.png

     

    然后外层迭代 记录/索引 这一层处理, 跳出循环 

    最终响应 0 条记录 

    39399d7a7a08478bb73bc9203f7dd828.png

     

     

     

     

     

  • 相关阅读:
    【树】在二叉树中增加一行 层序遍历
    File类和IO流
    C Primer Plus第九章编程练习答案
    前端比较简单,不需要架构?
    !与~有什么区别
    WebRTC 的多媒体音视频帧传输协议
    掌动智能:性能压力测试的重要性
    python(进阶篇)——多线程
    ISL1208时钟芯片 Linux下 i2c 设置报警时钟。
    自定义类型:结构体
  • 原文地址:https://blog.csdn.net/u011039332/article/details/131116528