当前位置: 首页 > news >正文

GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...

本篇文章关键字:优先队列排序算法、小顶堆、大顶堆

背景

接着 https://mengkang.net/1328.html 的案例,我们继续磕。

回顾下实验3中的例子

select `aid`,sum(`pv`) as num from article_rank force index(idx_aid_day_pv) where `day`>'20190115' group by aid order by num desc limit 10;

optimizer_trace.join_execution.steps的结果如下

{
  "join_execution": {
    "select#": 1,
    "steps": [
      {
        "creating_tmp_table": {
          "tmp_table_info": {
            "table": "intermediate_tmp_table",
            "row_length": 20,
            "key_length": 0,
            "unique_constraint": false,
            "location": "memory (heap)",
            "row_limit_estimate": 838860
          }
        }
      },
      {
        "filesort_information": [
          {
            "direction": "desc",
            "table": "intermediate_tmp_table",
            "field": "num"
          }
        ],
        "filesort_priority_queue_optimization": {
          "limit": 10,
          "rows_estimate": 649101,
          "row_size": 24,
          "memory_available": 262144,
          "chosen": true
        },
        "filesort_execution": [
        ],
        "filesort_summary": {
          "rows": 11,
          "examined_rows": 649091,
          "number_of_tmp_files": 0,
          "sort_buffer_size": 352,
          "sort_mode": "<sort_key, rowid>"
        }
      }
    ]
  }
}
关于这里的 filesort_priority_queue_optimization 算法可以参考 https://blog.csdn.net/qian520ao/article/details/80531150

在该案例中根据该结果可知,临时表使用的堆上的 memory 表。根据 https://mengkang.net/1336.html 实验中 gdb 调试打印可知道,临时表存的两个字段是aidnum

前面我们已经分析过对于 InnoDB 表来说 additional_fields 对比 rowid 来说,减少了回表,也就减少了磁盘访问,会被优先选择。但是要注意这是对于 InnoDB 来说的。而实验3是内存表,使用的是 memory 引擎。回表过程只是根据数据行的位置,直接访问内存得到数据,不会有磁盘访问(可以简单的理解为一个内存中的数组下标去找对应的元素),排序的列越少越好占的内存就越小,所以就选择了 rowid 排序。

还有一个原因就是我们这里使用了limit 10这样堆的成员个数比较小,所以占用的内存不会太大。不要忘了这里选择优先队列排序算法依然受到sort_buffer_size的限制。

优先队列排序执行步骤分析:

  1. 在临时表(未排序)中取出前 10 行,把其中的num(来源于sum(pv))和rowid作为10个元素构成一个小顶堆,也就是最小的 num 在堆顶。
  2. 取下一行,根据 num 的值和堆顶值作比较,如果该字大于堆顶的值,则替换掉。然后将新的堆做堆排序。
  3. 重复步骤2直到第 649091 行比较完成。
  4. 然后对最后的10行做一次回表查询其 aid,num。

rows_estimate

根据以上分析,先读取了 649091 行,然后回表又读取了 10 行,所以总共是 649101 行。
实验3的结果与之相吻合,但是其他的都是 1057 行,是怎么算出来的呢?

row_size

存储在临时表里时,都是 aidnum 字段,占用宽度是4+15是19字节。
为什么是实验3是24字节,其他是 additional_fields 排序都是36字节。

源码分析

看下里面的Sort_param

/**
  There are two record formats for sorting:
    |<key a><key b>...|<rowid>|
    /  sort_length    / ref_l /

  or with "addon fields"
    |<key a><key b>...|<null bits>|<field a><field b>...|
    /  sort_length    /         addon_length            /

  The packed format for "addon fields"
    |<key a><key b>...|<length>|<null bits>|<field a><field b>...|
    /  sort_length    /         addon_length                     /

  <key>       Fields are fixed-size, specially encoded with
              Field::make_sort_key() so we can do byte-by-byte compare.
  <length>    Contains the *actual* packed length (after packing) of
              everything after the sort keys.
              The size of the length field is 2 bytes,
              which should cover most use cases: addon data <= 65535 bytes.
              This is the same as max record size in MySQL.
  <null bits> One bit for each nullable field, indicating whether the field
              is null or not. May have size zero if no fields are nullable.
  <field xx>  Are stored with field->pack(), and retrieved with field->unpack().
              Addon fields within a record are stored consecutively, with no
              "holes" or padding. They will have zero size for NULL values.

 */
class Sort_param {
public:
  uint rec_length;            // Length of sorted records.
  uint sort_length;           // Length of sorted columns.
  uint ref_length;            // Length of record ref.
  uint addon_length;          // Length of added packed fields.
  uint res_length;            // Length of records in final sorted file/buffer.
  uint max_keys_per_buffer;   // Max keys / buffer.
  ha_rows max_rows;           // Select limit, or HA_POS_ERROR if unlimited.
  ha_rows examined_rows;      // Number of examined rows.
  TABLE *sort_form;           // For quicker make_sortkey.
  bool use_hash;              // Whether to use hash to distinguish cut JSON
  
  //...
};

trace 日志是在这里记录的
image.png

image.png

(gdb) b sortlength
Breakpoint 7 at 0xf20d84: file /root/newdb/mysql-server/sql/filesort.cc, line 2332.

image.png

image.png

这样就推断出了 rowid 排序时,优先队列排序里面的 row_size 为什么是 24 了。

小结

当是 rowid 排序时,参考上面的注释可知 row_size (也就是 param->rec_length)格式如下

|<key a><key b>...|<rowid>|
/  sort_length    / ref_l /

sort_length 就是 num 的长度 + 1字节(标识是可以为空)。所以源码里注释有问题,没有标识出每个排序字段可以为空的长度
rowid 的长度就是 table->file->ref_length 也就是 handler->ref_length

class handler :public Sql_alloc
{
  public:
    uchar *ref;                /* Pointer to current row */
  public:  
    /** Length of ref (1-8 or the clustered key length) */
    uint ref_length;
}

可以看到ref_length表示该行的指针长度。因为是64位服务器,所以长度是8字节,因此最后就是24字节啦。验证完毕。

相关文章:

  • leetcode388. Longest Absolute File Path
  • 后端_MYSQL
  • Java的Interrupt与线程中断
  • Go 领军人物谢孟军:智能制造渴望银弹,首先要摒弃偏见
  • Spark2.4.0源码分析之WorldCount ShuffleMapTask处理(八)
  • 技术总结(持续更新,偏自己看)
  • 小程序 setData 学问多
  • 洛谷P5163 WD与地图
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 轻松防止服务器被黑
  • spring cloud构建互联网分布式微服务云平台-服务网关zuul
  • 了解语音交互:从“若琪,今天杭州的天气”发生了什么?
  • 阿里云SLB出现502 Bad Gateway 错误排查解决方法
  • bat(DOS)常用命令详解
  • 力扣(LeetCode)357
  • 时间复杂度分析经典问题——最大子序列和
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • java中具有继承关系的类及其对象初始化顺序
  • JS题目及答案整理
  • LeetCode29.两数相除 JavaScript
  • Service Worker
  • vue-router 实现分析
  • vue总结
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 构建二叉树进行数值数组的去重及优化
  • 那些被忽略的 JavaScript 数组方法细节
  • 前言-如何学习区块链
  • 悄悄地说一个bug
  • 让你的分享飞起来——极光推出社会化分享组件
  • 用jQuery怎么做到前后端分离
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​io --- 处理流的核心工具​
  • ​一些不规范的GTID使用场景
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (13)Hive调优——动态分区导致的小文件问题
  • (14)Hive调优——合并小文件
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (五)关系数据库标准语言SQL
  • (转)socket Aio demo
  • (转)关于多人操作数据的处理策略
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .NET Framework杂记
  • .Net 垃圾回收机制原理(二)
  • .Net 路由处理厉害了
  • .net 提取注释生成API文档 帮助文档
  • .NetCore部署微服务(二)
  • .NET序列化 serializable,反序列化
  • .NET与 java通用的3DES加密解密方法
  • .NET中winform传递参数至Url并获得返回值或文件
  • .net中生成excel后调整宽度
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [52PJ] Java面向对象笔记(转自52 1510988116)