join语句的两种算法,分别是:NLJ和BNL

测试数据:

create table t1(id int primary key, a int, b int, index(a));
create table t2 like t1;
drop procedure idata;
delimiter ;;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=1000)do
insert into t1 values(i, 1001-i, i);
set i=i+1;
end while; set i=1;
while(i<=1000000)do
insert into t2 values(i, i, i);
set i=i+1;
end while; end;;
delimiter ;
call idata();

Multi-Range Read优化

MRR的设计思路就是:大多数数据都是按照主键递增的顺序插入得到的,所以我们可以认为,如果按照主键的递增顺序查询的话,多磁盘的读比较接近于顺序读,能够提升读的性能。
此时,执行语句将会变成这样:
  1. 根据索引a,定位满足条件的记录,将id值放入read_rnd_buffer中;
  2. 将read_rnd_buffer中的id进行递增排序
  3. 排序后的id数组,依次到主键 id索引中查找记录,并作为结果返回。
如果我们想稳定低使用MRR优化的话,需要设置set optimizer_switch="mrr_cost_based =off"参数
总结一下:MRR的核心就是,这条查询语句在索引a上做的是一个范围查询(多值查询),可以得到足够多的主键id,这样通过排序后,再去主键索引差数据,才能体现出“顺序性”

Batched key Access优化

MySQL在5.6版本后,引入了BKA算法,其实就是对NLJ算法的优化
NLJ的逻辑是,从驱动表t1,逐行取出a的值,再到驱动表t2去做join。
我们可以把表t1 的数据取出来一部分,先放到一个临时内存中,这个临时内存就是join_buffer
启动BKA算法的参数是:

set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

BNL性能优化

在通常情况下,我们可以直接在被驱动表上建立索引,这样就可以将BNL算法成NLJ算法了。但是有一些被驱动表不适合做索引,例如:
select * from t1 join t2 on (t1.b=t2.b) where t2.b>=1 and t2.b<=2000;

这句SQL表示,在经过where条件过滤,需要参与join的只有2000行数据。如果这条数据是一个低频的SQL,那么在为表t2建立一个字段b的索引,就很浪费了。
但是如果我们使用BNL算法,那么我们首先会将表t1存入join_buffer,然后扫描表t2与join_buffer中的数据进行比对,这里的数据是指所有的数据。这个判断等值条件的次数是1000*100万=10亿次。

这个时候,我们可以考虑使用临时表来优化,大致的思路是:
  1. 把表中t2满足条件的数据,先放在临时表tmp_t中;
  2. 为了让join可以使用BKA算法, 给临时表tmp_t的字段加上索引
  3. 让临时表和t1做join操作
create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;
insert into temp_t select * from t2 where b>=1 and b<=2000;
select * from t1 join temp_t on (t1.b=temp_t.b);

此时,可以明显看出,速度快了很多。
总结:
在被驱动表的字段上加索引
创建临时表,在临时表中加索引

hash join

我们可以自己在业务段,创建hash结构,然后将数据读出来,自己进行数组的匹配和数组集的组装。也可以提高join的性能。

总结:

BKA优化是MySQL内置支持的,建议使用
BNL效率低,建议转成BKA算法
临时表的方案,对于能提前过滤出小数据的join语句来说,效果很好
hash join的效果也是很好的,基于内存计算,路论上效果优于临时表

你知道如何优化Join语句吗?的更多相关文章

  1. 优化join语句

    Mysql4.1开始支持SQL的子查询.这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中.使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的 ...

  2. 35 | join语句怎么优化?

    在上一篇文章中,我和你介绍了 join 语句的两种算法,分别是 Index Nested-Loop Join(NLJ) 和 Block Nested-Loop Join(BNL). 我们发现在使用 N ...

  3. 如何用 SQL Tuning Advisor (STA) 优化SQL语句

    在Oracle10g之前,优化SQL是个比较费力的技术活,不停的分析执行计划,加hint,分析统计信息等等.在10g中,Oracle推出了自己的SQL优化辅助工具: SQL优化器(SQL Tuning ...

  4. Expert 诊断优化系列------------------语句调优三板斧

    前面三篇通过CPU.内存.磁盘三巨头,讲述了如何透过现在看本质,怎样定位服务器三巨头反映出的问题.为了方便阅读给出链接: SQL SERVER全面优化-------Expert for SQL Ser ...

  5. ORACLE常用SQL优化hint语句

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...

  6. mysql优化SQL语句的一般步骤及常用方法

    一.优化SQL语句的一般步骤 1. 通过show status命令了解各种SQL的执行频率 mysqladmin extended-status 或: show [session|global]sta ...

  7. 在优化SQL语句中使用虚拟索引

    定义:虚拟索引(virtual index) 是指没有创建对应的物理段的索引. 虚拟索引的目的:是在不损耗主机CPU,IO,磁盘空间去实际创建索引的情况下,来判断一个索引是否能够对SQL优化起到作用. ...

  8. mysql性能优化之数据库级别优化--优化sql语句

    一  优化SELECT语句 1.1 WHERE子句优化 本文暂时只讨论可以处理WHERE子句的优化,下面的一些实例使用SELECT语句,但是相同的优化同样适用DELETE和UPDATE语句中的WHER ...

  9. 022:SQL优化--JOIN算法

    目录 一. SQL优化--JOIN算法 1.1. JOIN 写法对比 2. JOIN的成本 3. JOIN算法 3.1. simple nested loop join 3.2. index nest ...

随机推荐

  1. CS184.1X 计算机图形学导论 罗德里格斯公式推导

    罗德里格斯公式推导 图1(复制自wiki) 按照教程里,以图1为例子,设k为旋转轴,v为原始向量. v以k为旋转轴旋转,旋转角度为θ,旋转后的向量为vrot. 首先我们对v进行分解,分解成一个平行于k ...

  2. 自学web前端达到什么水平,才能满足求职的标准?

    大多数野生程序员最棘手的问题就是如何依靠技术解决温饱,通俗来讲就是技术折现的问题. 如果是单纯出于兴趣,或者只是为了突击某一阶段或者某一项目技术壁垒,不跟就业挂钩的自学倒也是无关痛痒.但是当上岗成为自 ...

  3. 某PHP发卡系统SQL注入

    源码出自:https://www.0766city.com/yuanma/11217.html 安装好是这样的 审计 发现一处疑似注入的文件 地址:/other/submit.php 看到这个有个带入 ...

  4. 使用Docker搭建apache环境

    Docker搭建apache环境 前言 操作机:ubuntu16 x64 Dockers servion 18.09.7 下载镜像 使用docker pull 拉取最新的 apache镜像 命令:do ...

  5. 常用函数-Win-IP

    //************************************************************************* // 函数名: GetAppPath // 返回 ...

  6. WPF中的文本度量

    关于WPF中的文本度量,需要了解以下几个问题: WPF中支持一些常用的度量单位:px(device independent pixels).in(inches).cm(centimeters).pt( ...

  7. vue入门笔记(新手入门必看)

    一.什么是Vue? 1.    vue为我们提供了构建用户界面的渐进式框架,让我们不再去操作dom元素,直接对数据进行操作,让程序员不再浪费时间和精力在操作dom元素上,解放了双手,程序员只需要关心业 ...

  8. Intellij idea 一个窗口打开多模块并添加依赖

    打开多模块 ctrl+alt+shift+s 或者file->project sturcture 选择modules 添加 选择要添加的模块 选择从现有模块添加,不要选择从现在代码创建模块 添加 ...

  9. 小白学微信小程序

    奔着实用性的目的-测试孩子的认字量,开发了一个微信小程序-测字大王.上下班路上看书看了一个星期,代码前后共写一个星期.现在小程序已经对外开放,share下我的开发过程吧. 一 工具准备 首先先过一篇 ...

  10. javascript函数前面加~波浪线的作用

    如下,在函数前加上波浪号,其作用是把函数声明转换为表达式,这样就可以直接运行. ~function sayHello(){ console.log('hello'); }() 测试: 在console ...