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区正常业务的缓存影响减小。

相关推荐
l1t8 小时前
duckdb 1.6dev新增的.manual命令
开发语言·数据库
辉灰笔记8 小时前
第一篇:MySQL8.0生产备份实战|XtraBackup全自动全量+增量备份(钉钉告警+异地Binlog归档)
数据库·mysql·钉钉·运维开发
山峰哥9 小时前
‌Explain实战:打开数据库执行计划的黑盒‌
大数据·服务器·数据库·sql·深度优先·宽度优先
wzy06239 小时前
VIP + Orchestrator + 自定义脚本 MySQL 高可用方案
mysql·orchestrator
ClickHouseDB9 小时前
ClickHouse 26.6 版本发布说明
数据库
Wang's Blog9 小时前
Java框架快速入门:深入MyBatis-Plus高级DML操作(ID策略·逻辑删除·乐观锁)
java·数据库·mybatis
小二·20 小时前
RAG + 向量数据库实战:ChromaDB / Milvus / FAISS 选型与性能横评
数据库·milvus·faiss
矜持的左手21 小时前
电子小白的枕边书:电子学(The Art of Electronics)
数据库·restful
吴声子夜歌21 小时前
Redis 5.x——布隆过滤器
数据库·redis·缓存