当前位置: 首页 > 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
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • egg(89)--egg之redis的发布和订阅
  • es6--symbol
  • Golang-长连接-状态推送
  • markdown编辑器简评
  • Objective-C 中关联引用的概念
  • python_bomb----数据类型总结
  • Rancher如何对接Ceph-RBD块存储
  • Redis学习笔记 - pipline(流水线、管道)
  • webpack4 一点通
  • 前端技术周刊 2019-01-14:客户端存储
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 项目实战-Api的解决方案
  • 白色的风信子
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • Java总结 - String - 这篇请使劲喷我
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • Nginx实现动静分离
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • #1014 : Trie树
  • #mysql 8.0 踩坑日记
  • (2)(2.10) LTM telemetry
  • (3)nginx 配置(nginx.conf)
  • (java)关于Thread的挂起和恢复
  • (笔试题)分解质因式
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (十三)Flask之特殊装饰器详解
  • (转)ABI是什么
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)创业的注意事项
  • (转)德国人的记事本
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • *Django中的Ajax 纯js的书写样式1
  • .NET Core 成都线下面基会拉开序幕
  • .net framework profiles /.net framework 配置
  • .NET 命令行参数包含应用程序路径吗?