当前位置:网站首页>MySQL中回表的代价
MySQL中回表的代价
2022-07-06 17:21:00 【秀强】
回表的代价
对于下面这个查询语句来说:SELECT * FROM single_ table WHERE key1 > 'a' AND key1 < 'c';
我们可以选择下面这两种方式来执行。
- 以全表扫描的方式执行该查询
也就是直接扫描全部的聚簇索引记录,针对每一条聚簇索引记录,都判断搜索条件是否成立,如果成立则发送到客户端,否则跳过该记录。 - 使用 idx_key1 执行该查询
可以根据搜索条件 key1>a’ AND key1 < ‘c’ 得到对应的扫描区间(‘a’,‘c’),然后扫描该扫描区间中的二级索引记录。由于 idx_key1 索引的叶子节点存储的是不完整的用户记录,仅包含 key1、id 这两个列,而查询列表是*,这意味着我们需要获取每条二级索引记录对应的聚簇索引记录,也就是执行回表操作,在获取到完整的用户记录后再发送到客户端。
对于使用 InnoDB 存储引擎的表来说,索引中的数据页都必须存放在磁盘中,等到需要时再加载到内存中使用。这些数据页会被存放到磁盘中的一个或者多个文件中,页面的页号对应着该页在磁盘文件中的偏移量。以 16KB 大小的页面为例,页号为 0 的页面对应着这些文件中偏移量为 0 的位置,页号为 1 的页面对立着这些文件中偏移量为 16KB 的位置。
B+树的每层节点会使用双向链表连接起来,上一个节点和下一个节点的页号可以不必相邻。不过在实际实现中,InnoDB 还是尽量让同一个索引的叶子节点的页号按照顺序排列。
也就是说,idx_key1 在扫描区间(‘a’,‘e’)中的二级索引记录所在的页面的页号会尽可能相邻。即使这些页面的页号不相邻,但起码一个页面可以存放很多记录,也就是说在执行完一次页面 I/O 后,就可以把很多二级索引记录从磁盘加载到内存中。总而言之,就是读取在扫描区间(‘a’,‘e’)中的二级索引记录时,所付出的代价还是较小的。不过扫描区间(‘a’,‘e’)中的二级索引记录对应的 id 值的大小是毫无规律的,我们每读取一条二级索引记录,就需要根据该二级索引记录的 id 值到聚簇索引中执行回表操作。如果对应的聚簇索引记录所在的页面不在内存中,就需要将该页面从磁盘加载到内存中。由于要读取很多 id 值并不连续的聚簇索引记录,而且这些聚簇索引记录分布在不同的数据页中,这些数据页的页号也毫无规律,因此会造成大量的随机 I/O。
需要执行回表操作的记录越多,使用二级索引进行查询的性能也就越低,某些查询宁愿使用全表扫描也不使用二级索引。比如,假设 key1 值在 'a’~’c’之间的用户记录数量占全部记录数量的 99% 以上,如果使用 idx_key1 索引,则会有 99% 以上的 id 值需要执行回表操作。这还不如直接执行全表扫描。
那么在执行查询时,什么时候采用全表扫描,什么时候使用二级索引+回表的方式呢?这就是查询优化器应该做的工作。查询优化器会事先针对表中的记录计算一些统计数据,然后再利用这些统计数据或者访问表中的少量记录来计算需要行回表操作的记录数。如果需要执行回表操作的记录数越多,就越倾向于使用全表扫描,反之则倾向于使用二级索引+回表的方式。当然,查询优化器所做的分析工作没有这么简单,但大致上是这样一个过程。
一般情况下,可以给查询语句指定 LIMIT 子句来限制查询返回的记录数,这可能会让查询优化器倾向于选择使用二级索引+回表的方式进行查询,原因是回表的记录越少,性能提开就越高。比如,上面的查询语句可以改写成下面这样:SELECT * FROM single_table WHERE key1 >'a' AND key1 < 'c' LIMIT 10;
添加了 LIMIT 10 子句后的查询语句更容易让查询优化器采用二级索引+回表的方式来执行。
对于需要对结果进行排序的查询,如果在采用二级索引执行查询时需要执行回表操作的记录特别多,也倾向于使用全表扫描+文件排序的方式执行查询。比如下面这个查询语句:SELECT * FROM single_table ORDER BY key1;
由于查询列表是 *
,如果使用二级索引进行排序,则需要对所有二级索引记录执行回表操作。这样操作的成本还不如直接遍历聚簇索引然后再进行文件排序低,所以查询优化器会倾向于使用全表扫描的方式执行查询。如果添加了 LIMIT 子句,比如下面这个查询语句:SELECT * FROM single_table ORDER BY key1 LIMIT 10;
这个查询语句需要执行回表操作的记录特别少,查询优化器就会倾向于使用二级索引+回表的方式来执行。
边栏推荐
- Part VI, STM32 pulse width modulation (PWM) programming
- [HFCTF2020]BabyUpload session解析引擎
- Zabbix 5.0:通过LLD方式自动化监控阿里云RDS
- 动态规划思想《从入门到放弃》
- Summary of being a microservice R & D Engineer in the past year
- 深度学习框架TF安装
- [C language] dynamic address book
- Slam d'attention: un slam visuel monoculaire appris de l'attention humaine
- Niuke cold training camp 6B (Freund has no green name level)
- pytorch之数据类型tensor
猜你喜欢
C9 colleges and universities, doctoral students make a statement of nature!
Learn self 3D representation like ray tracing ego3rt
Niuke cold training camp 6B (Freund has no green name level)
Dell笔记本周期性闪屏故障
第六篇,STM32脉冲宽度调制(PWM)编程
.class文件的字节码结构
[software reverse automation] complete collection of reverse tools
Stm32f407 ------- DAC digital to analog conversion
深度学习之线性代数
Service asynchronous communication
随机推荐
界面控件DevExpress WinForms皮肤编辑器的这个补丁,你了解了吗?
代码克隆的优缺点
"Exquisite store manager" youth entrepreneurship incubation camp - the first phase of Shunde market has been successfully completed!
Deep understanding of distributed cache design
Grc: personal information protection law, personal privacy, corporate risk compliance governance
[hfctf2020]babyupload session parsing engine
Threejs image deformation enlarge full screen animation JS special effect
【批處理DOS-CMD命令-匯總和小結】-字符串搜索、查找、篩選命令(find、findstr),Find和findstr的區別和辨析
.class文件的字节码结构
迈动互联中标北京人寿保险,助推客户提升品牌价值
Deep learning framework TF installation
mysql: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such
【JokerのZYNQ7020】AXI_ EMC。
What kind of experience is it to realize real-time collaboration in jupyter
Dr selection of OSPF configuration for Huawei devices
mysql: error while loading shared libraries: libtinfo. so. 5: cannot open shared object file: No such
Openjudge noi 1.7 10: simple password
[Batch dos - cmd Command - Summary and Summary] - String search, find, Filter Commands (FIND, findstr), differentiation and Analysis of Find and findstr
[HFCTF2020]BabyUpload session解析引擎
【JVM调优实战100例】05——方法区调优实战(下)