【MySQL·8.0·源码】MySQL 表的扫描方式

前言

在进一步介绍 MySQL 优化器时,先来了解一下 MySQL 单表都有哪些扫描方式。
单表扫描方法是基表的读取基础,也是完成表连接的基础,熟悉了基表的基本扫描方式,
即可以倒推理解 MySQL 优化器层的诸多考量。

基表,即数据库中的原始表,与之对应的是视图、物化临时表或其他形式的派生表(中间生成的)
基表是直接存储实际数据的,在查询语法树中,一般叶子节点所对应的表为基表,
MySQL 语法树大致结构可以参考【MySQL·8.0·源码】MySQL 语法树结构

MySQL 支持不同的存储引擎,以 InnoDB 举例,InnoDB 存储引擎采用的是
一种 Index-organized(clustered index)的方式来组织数据。
InnoDB 数据存储的一些关键特点:

  • InnoDB 内部数据分割成固定大小的数据页(16KB)
  • 每个数据页中存储有序的数据行,且按照主键(即聚簇索引)顺序存储,主键本身也是一颗 B+ 树
  • 非主键索引即二级索引叶子节点存储主键值,而非实际数据行,想通过二级索引定位到实际行要通过主键跳转

对物理结构感兴趣的可以去看 innodb_ruby 工程
和 innodb_diagrams

AccessMethods

对基表的读取方式,数据库中有专门的术语,称为 access method
想要读取一张表的记录,无非两种方式:

  • 直接从表存储的页上进行扫描,即直接做表扫描
  • 通过索引检索记录数据

直接表扫描比较简单,因为记录行已经是按某种顺序存储在数据页上的,直接扫描 data page
索引扫描,根据索引不同(clustered key、second index key),可以衍生出多种扫描方式

TABLE_SCAN

在 TABLE_SCAN 中,所有非空的数据页都会被扫描一次,无论被扫描的数据页是否包含所期望的记录,
但仅只会被扫描一次,然后可以对扫描的记录进行谓词比较,即可返回正确所期望的结果

INDEX_SCAN

不同类型索引的不同处理

  • clustered index
    由于 clustered index 的特性:
    即 tuple 是按着 clustered index 的顺序插入到 data page 中的,所以 clustered index 的键值顺序和 data page 中的 tuple
    的物理顺序是一致的,所以扫描 clustered index 也意味着扫描了一次 table data page。

  • second index
    普通的二级索引不一样,由于二级索引上的键值顺序是以二级索引列为准,而非 tuple 实际的物理顺序,所以
    如果 data 同一个 page 上两个 tuple 在二级索引列上不是紧挨着的顺序,则在扫描二级索引时,该 data page 可能
    会被多次扫描到。

同 TABLE_SCAN 要完整的扫描一次所有的非空 data page 不同,INDEX_SCAN 一般无需扫描整个表,可以
通过指定索引的起始键值和终止键值,仅扫描索引值范围内的记录即可。

MySQL 的 Access Method

TABLE_SCAN

MySQL 的 TABLE_SCAN 没有特别的不同,唯一特殊的是对常量表的特别处理

  • SYSTEM
    当 MySQL 发现基表只有一行行记录时,MySQL 会专门将其访问类型标记为 system,并且会直接记录值
    并且物化处理,以显著简化 join 顺序选择
    在这里插入图片描述
  • ALL
    MySQL 将完整的 table scan 标记为 ALL,当为 ALL 时,会对所有非空的 data page 进行完整扫描一次
    在这里插入图片描述

INDEX_SCAN

MySQL 基于索引,从减少扫描代价出发,细化了很多种扫描方式

等值查询

  • CONST
    基表对于给定的查询条件中确定只有一行匹配名中的行,这种访问类型被标记为 const
    场景为走主键或唯一索引键精确匹配等值查询
    在这里插入图片描述

  • EQ_REF
    eq_ref 也是基表的一种访问方式,和 const 一样,也是使用 primary key 或者 unique key not null 进行数据检索,
    但和 const 不同的是,EQ_REF 是为在 join 查询中的内表连接的一种访问方式
    假如说 const 是 <table_name>.<key_column> = <const_value>,例如:t1.c1 = 5,t1.c1 上有主键或者不为空的唯一索引
    那么 EQ_REF 为 <inner_table_name>.<key_column> = <outer_table_name>.<column>,例如:it1.c1 = ot1.c2,it1.c1 上有主键或者不为空的唯一索引
    在这里插入图片描述

  • REF
    如果仍然是做等值查询,但是选择的索引非 primary key 或者 unique index,也就是说可能匹配到多行的结果,
    MySQL 会将其标记为 ref 的访问类型
    在这里插入图片描述

  • REF_OR_NULL
    当给定的查询条件中涉及到 NULL 值查询时,例如:

    WHERE <key_column> IS NULL;
    WHERE <key_column> <=> NULL;
    WHERE <key_column> = const OR <key_column> IS NULL;
    

    此种扫描方式和 REF 相同,唯一不同的是额外会扫描 NULL 值

范围查询

  • INDEX
    如果不用考虑任何性能,那么对于走索引的一个范围查询,最简单的方式就是不管三七二十一,对索引树的叶子结点全部
    扫描一次进行然后继续对比,匹配的再进行一次回表取记录即可
    在这里插入图片描述
    • Using index
      对于二级索引扫描,如果 select fields即查询列表中,仅仅需要包含在二级索引列上的字段,那么
      回表取行记录的动作即可避免,少了回表的 IO 操作
      在这里插入图片描述
  • RANGE
    虽然一般来说,索引 index page 比数据 data page 来的更小,但如果每次都做一次索引 page 全扫描,
    代价也很高,而且根本发挥不出索引的最大作用,索引最大的作用在于可以根据给定的索引值快速定位到其
    在索引上的位置
    • INDEX_RANGE_SCAN
      所以,如果给定的条件是一个范围,那么完全可以定位到范围的起始位置,然后扫描索引到结束位置即可
      例如:

      WHERE <key_column> >= 3 and <key_column> <=20
      

      在这里插入图片描述

      这个范围可以进一步拓展到任何以下的操作符:=, <>, >, >=, <, <=, IS NULL, <=>, BEWTEEN, LIKE, 或者 IN()

    • INDEX_SKIP_SCAN
      我们知道,如果要使用索引扫描,那么条件必须满足索引的最左前缀原则:
      例如 key(col1, col2, col3),那么 where 条件必须为:

       WHERE col1 <opcode> constWHERE col1 <comparison> const1 and col2 <comparison> const2WHERE col1 <comparison> const1 and col2 <comparison> const2 and col3 <comparison> const3
      

      这种形式,那假如 WHERE 条件只包含 col2 的话,还要怎么仍然借助这个索引来扫描呢
      可以先读取到 key col1 的第一个值,然后与 col2 拼成新的范围:
      <col1_first_value>, start<col2_first_value>, end
      然后跳到 col1的下一个不同的值,继续
      拼成新的范围:
      <col1_second_diff_value>, start<col1_second_diff_value>, end
      一直扫描完整个索引,此种相对于扫描整个索引而言,不断跳过了 col1 相同的值部分,如果该
      索引 col1 上的值具有比较稀疏的特性,那么相对于扫描整个索引会减少很多部分的扫描
      在这里插入图片描述

    • MRR(Multi-Range Read)
      当 WHERE 给定的条件中,不止一个 RANGE,即给定了索引上的多个 start, end 范围段
      那么就需要在索引上对多个 RANGE 进行扫描,由于 Table_rows 是以聚簇索引的顺序组织的
      而 second index 二级索引上邻近的 key 值,聚餐索引上可能相差很大,那么扫描一个 second index 的 page,
      可能需要回表多个 data page,而同一个 data page 也可能会被扫描到多次
      在这里插入图片描述
      为了避免 data page 的随机扫描和同一个 page 的多次扫描,我们仅仅需要在回表前,对回表的 primary key 进行排序处理即可
      在这里插入图片描述

    • GROUP_INDEX_SKIP_SCAN
      假如有个查询需求,需要查某个列的 distinct 值,或者 group by 之后的值 MIN()/MAX() 值,
      最简单的方式是扫描整个数据页,然后分组排序后,取 DISTINCT/MIN/MAX 值
      但由于索引本身就有序并且完成了 group by 工作,如果可以直接借助于这个索引的有序性,
      那么扫描整个索引就可以避免二次排序的开销

      SELECT DISTINCT Key_col1 from t1;
      SELECT MAX(key_col2), key_col1 from t1 WHERE key_col1 = 1 AND key_col2 < 2 GROUP BY key_col1;
      
    进而类似于 INDEX_SKIP_SCAN,再做一次对相同的 key 值进行 skip 动作,即可以跳过了索引上相同的段,
    这样相比较与索引扫描而言,减少了很多的索引扫描,索引稀疏性越好,性能就会相对更好
    在这里插入图片描述
    • INDEX_MERGE
      对于同一个索引的 RANGE 查询,无非是点值查询,范围查询,多范围查询,甚至遍历整个索引
      但如果对 WHERE 条件分析后,发现针对不同的范围,可以走不同的索引,那么就可以通过多个索引来进行检索
      但如果简单地借助于多个索引进行检索,则不同的索引可能回表到同一行记录,这样就可能造成返回重复记录
      为了避免重复记录的返回,需要对多个索引的结果进行去重处理
      去重处理的 merge 按行为又可以分为 union(并集)、intersections(交集)和 unions-of-intersections(交集后的并集)
      • Index Merge Intersection
        示例:

         SELECT * FROM tbl_name WHERE key1_col1 = 1 AND key1_col2 = 2 AND key2_col = 2;
        

        key1: 索引 1,联合索引,字段为 col1 和 col2
        key2: 索引 2

        选择索引 key1 或者 key2 分别进行 range 扫描,然后取交集
        在这里插入图片描述

      • Index Merge Union
        示例:

          SELECT * FROM t1 WHERE key1 = 1 OR key2 = 2 OR key3 = 3;
        

        选择 key1key2key3 分别进行索引扫描,然后对结果取并集
        在这里插入图片描述

      • Index Merge Sort-Union
        Sort-union 和 union 访问方式类似,区别在于,sort-union 需要先获取 rowid 之后,在返回行记录之前进行排序处理
        示例:

        SELECT * FROM tbl_nameWHERE key_col1 < 10 OR key_col2 < 20;SELECT * FROM tbl_nameWHERE (key_col1 > 10 OR key_col2 = 20) AND nonkey_col = 30;
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/594945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows XP SP1源代码编译方法(笔记)

NT版本 : 5.1 编译号 &#xff1a;2600 编译时间 : 2001年8月17日11点48分 第一步 : 搭建编译环境 使用VMWare搭建Windows XP的编译环境&#xff0c;注意系统要使用英文版。 第二步 : 设置编译参数 1.将原代码解压到虚拟机的XP系统中的C盘C:\NT目录或者D盘D:\NT目录下…

myysql的正则表达式

上周遇见一个需求&#xff0c;有这样一棵树&#xff1a; 点击上级&#xff0c;展现所有子集&#xff0c;点击集团&#xff0c;显示所有产线&#xff08;例子&#xff09; 这个时候有两种方式&#xff1a; 添加产线时&#xff0c;将集团、事业部、公司、车间的id存起来。 然后…

人脸关键点检测dlib安装

dlib 库是一个用来人脸关键点检测的 python 库&#xff0c;但因为其是 C 编写&#xff08;或需要 C编译&#xff1f;&#xff09;&#xff0c;使得我们在安装时遇到各种各样问题。笔者在不同电脑上安装遇到的问题都不同&#xff0c;但最后经过搜索&#xff0c;都解决了&#xf…

数据结构【查找篇】

数据结构【查找篇】 文章目录 数据结构【查找篇】前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f; 目录一、顺序查找二、折半查找三、 二叉排序树的查找四、红黑树 结语 前言 为什么突然想学算法了&#xff1f; > 用较为“官方”的语言讲&am…

Git | tag相关命令

语法命令 git tag -h usage: git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]<tagname> [<head>]or: git tag -d <tagname>...or: git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit&g…

普中STM32-PZ6806L开发板(HAL库函数实现-读取内部温度)

简介 主芯片STM32F103ZET6&#xff0c;读取内部温度其他知识 内部温度所在ADC通道 温度计算公式 V25跟Avg_Slope值 参考文档 stm32f103ze.pdf 电压计算公式 Vout Vref * (D / 2^n) 其中Vref代表参考电压&#xff0c; n为ADC的位数&#xff0c; D为ADC输入的数字信号。 实现…

人工智能在银行运营中的运用

机器学习在金融领域的运用&#xff1a;银行如何以最优的方式抓住 AI 机会&#xff1f; 大型企业若想获得超越竞争对手的优势&#xff0c;那么采用 AI 作为其业务战略是他们的重要任务&#xff0c;而在这方面&#xff0c;大型银行走在了前面。银行开始将 AI 和机器学习应用于前…

201.【2023年华为OD机试真题(C卷)】最长子字符串的长度(一)(滑动窗口算法-JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目二.解题思路三.题解代码Python题解代码JAVA题解…

了解并使用django-rest-framework-jwt

一 JWT认证 在用户注册或登录后&#xff0c;我们想记录用户的登录状态&#xff0c;或者为用户创建身份认证的凭证。我们不再使用Session认证机制&#xff0c;而使用Json Web Token&#xff08;本质就是token&#xff09;认证机制。 Json web token (JWT), 是为了在网络应用环…

什么是跨域以及怎么处理跨域问题

文章目录 什么是跨域&#xff1f;跨域问题常见场景怎么处理跨域1、配置代理2、CORS&#xff08;跨域资源共享&#xff09;3、JSONP&#xff08;仅限 GET 请求&#xff09;4、使用 WebSocket 注意事项&#xff1a; 什么是跨域&#xff1f; 跨域&#xff08;Cross-Origin&#x…

专题一_双指针(一)

文章目录 283.移动零题目解析讲解算法原理扩展编写代码 1089.复习零题目解析讲解算法原理编写代码 202.快乐数题目解析讲解算法原理证明编写代码 11.盛最多水的容器题目解析讲解算法原理暴力解法优秀的解法时间复杂度分析 编写代码 283.移动零 题目链接 题目解析 题目还是比较…

ThinkPHP6.0任意文件上传 PHPSESSION 已亲自复现

ThinkPHP6.0任意文件上传 PHPSESSION 已亲自复现 漏洞名称漏洞描述影响版本 漏洞复现环境搭建安装thinkphp6漏洞信息配置 漏洞利用 修复建议 漏洞名称 漏洞描述 2020年1月10日&#xff0c;ThinkPHP团队发布一个补丁更新&#xff0c;修复了一处由不安全的SessionId导致的任意文…

【GlobalMapper精品教程】069:中文属性表乱码问题及解决方法

参考阅读:【ArcGIS Pro微课1000例】0012:ArcGIS Pro属性表中文乱码完美解决办法汇总 文章目录 一、Globalmapper默认字符集设置二、shp属性表乱码三、转出的kmz乱码一、Globalmapper默认字符集设置 中文字体乱码通常是由字符编码不匹配造成的。 打开Globalmapper软件,点击工…

【动态规划】【字符串】扰乱字符串

作者推荐 视频算法专题 涉及知识点 动态规划 字符串 LeetCode87扰乱字符串 使用下面描述的算法可以扰乱字符串 s 得到字符串 t &#xff1a; 如果字符串的长度为 1 &#xff0c;算法停止 如果字符串的长度 > 1 &#xff0c;执行下述步骤&#xff1a; 在一个随机下标处将…

[设计模式 Go实现] 行为型~备忘录模式

备忘录模式用于保存程序内部状态到外部&#xff0c;又不希望暴露内部状态的情形。 程序内部状态使用窄接口船体给外部进行存储&#xff0c;从而不暴露程序实现细节。 备忘录模式同时可以离线保存内部状态&#xff0c;如保存到数据库&#xff0c;文件等。 memento.go packag…

java struts2教务管理系统Myeclipse开发mysql数据库struts2结构java编程计算机网页项目

一、源码特点 java struts2 教务管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助 struts2 框架开发&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库…

作用域和作用域链(js的问题)

• 全局作用域&#xff0c;函数作用域 • 作用域链 • 作用域scope: 一个变量的可用范围 • 作用域链scope chain&#xff1a;以当前作用域的scope属性为起点&#xff0c;依次引用每个AO,直到window结束&#xff0c;行成多级引用关系 js作用域ES5 …

常用日志查看方法 log | journalctl | messages

一、【说在前面】 写之前吐槽一下&#xff0c;我在从业中发现&#xff0c;很多人喜欢鼓吹XXX比较吃经验&#xff0c;我早期也比较信奉这一点&#xff0c;感觉各行各业应该都有自己的玄学解决问题的方式。 但是笔者也发现很多做了很多年的员工&#xff0c;遇到了问题就是在常用…

向爬虫而生---Redis 基石篇5 <拓展Zset>

前言: 基础操作篇最后一环节,就是这个了! reids里面的有序集合... 向爬虫而生---Redis 基石篇4 &#xff1c;拓展Set&#xff1e;-CSDN博客 向爬虫而生---Redis 基石篇3 &#xff1c;拓展List&#xff1e;-CSDN博客 向爬虫而生---Redis 基石篇2 &#xff1c;拓展Hash&#x…

【ikbp】数据可视化DataV

天天查询一些数据&#xff0c;希望来一个托拉拽的展示&#xff0c;部署体验一下可视化大屏 快速搭建快速查询实时更新简单易用 启动服务 数据可视化 静态查询 配置数据 过滤数据 分享