mysql join语句、全表扫描 执行优化与访问冷数据对内存命中率的影响

文章目录

    • join执行逻辑
      • [Index Nested_Loop Join(NLJ)](#Index Nested_Loop Join(NLJ))
        • [MMR(Mutli-Range Read) 优化](#MMR(Mutli-Range Read) 优化)
        • [BKA(Batched Key Access)算法](#BKA(Batched Key Access)算法)
      • [Simple Nested_Loop Join](#Simple Nested_Loop Join)
      • [Block Nested-Loop Join(BLJ)](#Block Nested-Loop Join(BLJ))
        • [join buffer 一次放不下 驱动表](#join buffer 一次放不下 驱动表)
        • [join buffer优化的影响:主要影响缓存命中率](#join buffer优化的影响:主要影响缓存命中率)
        • 临时表
      • 选用t1还是t2做驱动表
    • 全表扫描性能优化

join执行逻辑

Index Nested_Loop Join(NLJ)

Index Nested_Loop Join:被驱动表上有索引,查的就快一点

复制代码
// 背景条件:t1表N条数据,t2表M条,t2表在a上有索引,N << M
select * from t1 join t2 on (t1.a=t2.a);

驱动表:t1 (小表)

被驱动表:t2,t2上有a索引,走索引再回表查询

图片来自极客时间 丁奇 MySQL实战45讲

时间复杂度:N + N * 2 * log2M

N(t1全表扫描) + (t2表要查N次)N * 2(a索引上搜索一次+回表搜索一次) * log2M(树查找)

MMR(Mutli-Range Read) 优化

正常回表都是一个一个回表查,但是如果我们是范围查,可以一组查询按主键id排序后再查(主键ID表上是有序的)就更快

在read_rnd_buffer中做排序

|

图片来自极客时间 丁奇 MySQL实战45讲
BKA(Batched Key Access)算法

按照MMR的思路,NLJ本来是从t1一条一条取数据去t2 a索引上找的,我们可以每次多取点(看join buffer的大小)到join buffer上排个序再一起MRR,去a索引上找。

Simple Nested_Loop Join

如果被驱动表上没有索引,那t1、t2都全表扫描

时间复杂度:N + N * M

Block Nested-Loop Join(BLJ)

如果被驱动表上没有索引,做点优化:join_buffer 把驱动表存到内存里,这样对比的时候快点

原先是从磁盘上一行一行的读t1,拿到a的值再去t2表上查;现在把t1整个存在内存join buffer中,在一行一行的拿t2和join buffer中的数据做比较

时间复杂度:N + M,内存判断次数:N * M

join buffer 一次放不下 驱动表

分段放,每部分都执行上面的步骤。

时间复杂度:N + K * M // K就是分成了多少段,内存判断次数:N * M

join buffer优化的影响:主要影响缓存命中率

大表join会导致冷数据进入内存缓冲区,影响正常业务缓存命中率。由于join buffer优化,导致被驱动表被多次扫描,就算lru 有young区、old区,热数据也有被顶掉的风险。所以慎用BLJ,最好在被驱动表上建索引,如果仅临时操作一次,建索引比较浪费,可以考虑使用临时表

临时表

临时表的特点:每个事务独立有的,会话结束时自动销毁,show tables访问不到;对于同名表和临时表,临时表优先级高于同名表;

对于偶尔join大表,可以考虑使用临时表

选用t1还是t2做驱动表

选按照各自条件过滤完后,数据较少的表做驱动表。

从上面的时间复杂度可以看到:join buffer能装下,选谁都行;其他情况:N的影响大于M,所以N越小越好

全表扫描性能优化

对sever层的影响

图片来自极客时间 丁奇 MySQL实战45讲

服务端并不需要保存完整的结果集,数据是一段一段传给客户端的:

  1. 先取一行写道net buffer pool中。这个内存的大小由参数net_buffer_length定义,默认16KB
  2. 重复,直至net buffer pool写慢,调用网络接口发出去
  3. 成功,就清空net buffer,重复
  4. 直至发送失败,socket send buffer写慢了,进入等待;等能写了再发

对innodb的影响:主要影响缓存命中率

buffer pool结构

buffer pool使用lru算法,对最近最少使用的数据进行淘汰。全表扫描会导致短时间内大量冷数据进入buffer pool,影响正常业务的缓存命中率。

针对全表扫描的buffer pool优化
  • 若此时访问P3,由于P3在young区,所以使用之前的lru算法,移动到链表首部
  • 若此时要访问一个不存在在buffer pool的数据页,依旧淘汰队尾Pm,但新插入的元素放在old区队首Px位置(// 先观察一下)
  • old区的数据,每次访问前都要做判断:
    • 在链表存在时间超过1s,ok,可以移动到young队首
    • 没到1s,位置不变。innodb_old_blocks_time = 1000ms

增加old区,因为全表扫描的冷数据不会变频繁访问,所以一般就在old区,对young区正常业务的缓存影响减小。

相关推荐
咖丨喱7 分钟前
【Action帧简要分析】
服务器·数据库·asp.net
没饭吃!8 分钟前
NHibernate案例
数据库·hibernate
泷羽Sec-静安30 分钟前
OSCP官方靶场-Solstice WP
服务器·网络·数据库
IvanCodes40 分钟前
Oracle 视图
大数据·数据库·sql·oracle
Trust yourself2431 小时前
使用阿里云/腾讯云安装完成mysql使用不了
mysql·阿里云·腾讯云
德育处主任Pro1 小时前
「py数据分析」04如何将 Python 爬取的数据保存为 CSV 文件
数据库·python·数据分析
许白掰1 小时前
Linux入门篇学习——Linux 编写第一个自己的命令
linux·运维·数据库·嵌入式硬件·学习
打不了嗝 ᥬ᭄2 小时前
文件系统----底层架构
linux·运维·数据库
亲爱的非洲野猪3 小时前
Oracle与MySQL详细对比
数据库·mysql·oracle
Matrix703 小时前
Navicat实现MySQL数据传输与同步完整指南
数据库·mysql