zoukankan      html  css  js  c++  java
  • 数据库JOIN语句优化

    一、JOIN语句优化

    join的种类有哪些? 彼此的区别?

    join有哪些算法?

    join语句如何优化

    1、join的种类有哪些? 彼此的区别?

     还有一种join

    select  *   from  A a corss join   B b;

    笛卡尔积连接。行数是A表和B表的乘积。

    如果corss join带有on子句,就相当于inner  join

    select  *   from  A a corss join   B b where a.id   = b.id ;

    2、join有哪些算法?

    JOIN算法1: Nested-Loop  Join(NLJ)  嵌套循环

    三张表

     伪代码

    JOIN算法2-Block Nested-Loop Join (BNLJ) 块循环嵌套Join

     伪代码

     引入join_buffer 降低了内层扫描的次数。

    使用join buffer的条件

    连接类型是All,index或range

    第一个nonconst table(非常量表) 不会分配join buffer,即使类型是All或者index。

    join buffer只会缓存需要的字段,而非整行数据。

    可通过join_buffer_size 变量设置join buffer大小

    每个能被缓存的join都会分配一个join buffer,一个查询可能有多个join buffer

    补充: join buffer在连接之前分配,在执行查询之后释放。

    如何知道一条SQL使用了BNLJ算法呢?

     出现Using join  buffer(Block Nested Loop) 表示使用了BNLJ。

    JOIN算法3-Batched Key Access Join(BKA) 批量键值访问

    MySQL 5.6 引入

    BKA的基石: Multi  Range  Read(MRR)

    MRR核心: 将随机IO转换成顺序IO,从而提升性能

    MRR参数

    1、optimizer_switch 的子参数

        mrr: 是否开启mrr, on开启,off关闭

        mrr_cost_based: 表示是否要开启基于成本计算的MRR

    2、read_rnd_buffer_size: 指定mrr缓存大小

    SHOW VARIABLES LIKE '%optimizer_switch%'

    返回: *** mrr=on,mrr_cost_based=on ***

    默认mrr是开启的,基于成本的mrr也是开启的。

    SHOW VARIABLES LIKE '%read_rnd_buffer_size%'

     默认是256K

    JOIN算法4-HASH JOIN

    MySQL 8.0.18引入,用来替代BNLJ

    join buffer缓存外部循环的hash表,内层循环遍历时到hash表匹配

    HASH JOIN注意点

    1、MySQL 8.0.18才引入,且有很多限制,比如不能作用于外连接,比如left join/right join等等。从8.0.20开始,限制少了很多,建议使用8.0.20或者更高的版本

    2、从MySQL 8.0.18开始,hash join的join buffer是递增分配的,这意味着,你可以为将join_buffer_size 设置的比较大。 而在MySQL 8.0.18中,如果你使用了外连接,

    外连接没法使用hash join,此时join_buffer_size会按照你设置的值直接分配内存。因此join_buffer_size还得谨慎设置。

     3、从MySQL 8.0.20开始,BNLJ已被删除了,用hash join代替了BNLJ

    二、如何优化JOIN语句

    1、启动表 vs 被驱动表

    外层循环的表是驱动表,内存循环的表是被驱动表。

    如下图,t1是t2的驱动表,t2是t1的被驱动表。t2是t3的驱动表,t3是t2的被驱动表。

    2、JOIN调优原则

    调优原则1

    1) 用小表驱动大表

    一般无需人工考虑,关联查询优化器会自动选择最优的执行顺序

    如果优化器抽风,可使用STRAIGHT_JOIN

    如何确定哪张表是小表,哪张表是大表?

    EXPLAIN SELECT * FROM employees e
    LEFT JOIN salaries s ON e.emp_no = s.emp_no
    WHERE e.emp_no = 10001;

    id都是1, 所以employees e 是驱动表。 

    EXPLAIN
    SELECT * FROM employees e LEFT JOIN dept_emp de ON e.`emp_no` = de.`emp_no`
    LEFT JOIN departments d ON de.`dept_no` = d.`dept_no`
    WHERE e.`emp_no` = 10001

     先操作e表,再操作de表,最后操作d表

    2) 如果有where条件,应当要能够使用索引,并尽可能减少外层循环的数据量。

    3) join的字段尽量创建索引

      join字段的类型要保持一致(如一张表userId为int,另外一张表的userId为varchar),否则索引无法生效。

    4)  尽量减少扫描的行数(explain-rows)

      尽量控制在百万以内(经验之谈,仅供参考)

    5) 参与join的表不要太多(因为扫描表的数据越多)

       阿里编程规约建议不超过3张

      如果业务要多张表的join,可以做如下修改

    -- 拆分前
    SELECT * FROM employees e LEFT JOIN dept_emp de ON e.`emp_no` = de.`emp_no`
    LEFT JOIN departments d ON de.`dept_no` = d.`dept_no`
    WHERE e.`emp_no` = 10001
    
    -- 拆分后
    SELECT * FROM employees WHERE emp_no =  10001
    SELECT * FROM dept_emp WHERE emp_no =  10001
    SELECT * FROM departments WHERE dept_no = 'd005'
    

     这里是三张表,只是举个例子。一般三张表是可接受的。 

    6) 如果被驱动表的join字段用不了索引,且内存较为充足,可以考虑把join buffer设置得大一些。

    join buffer可以降低内部循环次数,从而提高性能。

    作者:Work Hard Work Smart
    出处:http://www.cnblogs.com/linlf03/
    欢迎任何形式的转载,未经作者同意,请保留此段声明!

  • 相关阅读:
    微服务架构有哪些优势?
    Java 线程数过多会造成什么异常?
    Java 死锁以及如何避免?
    抽象的(abstract)方法是否可同时是静态的(static), 是否可同时是本地方法(native),是否可同时被 synchronized 修饰?
    内部类可以引用它的包含类(外部类)的成员吗?有没有 什么限制?
    CSS选取第几个标签元素:nth-child、first-child、last-child
    数据库约束
    DQL查询语句
    网络编程(客户端,服务端文件上传下载)
    缓冲流,转换流
  • 原文地址:https://www.cnblogs.com/linlf03/p/14206802.html
Copyright © 2011-2022 走看看