zoukankan      html  css  js  c++  java
  • MySQL连接查询区别及原理

    在实操之中,对于join、left join、right join通常情况下也是仅仅用到了left join,对于其他几种,心存疑惑,因此对几种join查询、以及原理做个记录。

    1.left、right、inner join 的区别

    创建表t1、t2

    CREATE TABLE `t2` (
      `id` int(11) NOT NULL,
      `a` int(11) DEFAULT NULL,
      `b` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `a` (`a`)
    ) ENGINE=InnoDB;
    ​
    create table t1 like t2;

    t1、t2分别插入5条数据

    delimiter ;;
    create procedure idata()
    begin
      declare i int;
      set i=1;
      while(i<=5)do
        insert into t1 values(i, i, i);
        set i=i+1;
      end while;
    end;;
    delimiter ;
    call idata();
    ​
    insert into t2 select * from t1 where a <= 4;
    insert into t2 values(6, 6, 6);

    left join 会查询出左表所有的数据,以及右表能连接上的字段

    select * from t1 left join t2 on t1.id = t2.id;

    right join 会查询出右表所有的数据,以及左表能连接上的字段

    select * from t1 right join t2 on t1.id = t2.id;

    inner join(等值连接) 只返回两个表中联结字段相等的行

    select * from t1 inner join t2 on t1.id = t2.id;

     

    2.连接查询原理

    为了后面结果更为清晰,往t1再插入15条数据:

    drop procedure idata;
    delimiter ;;
    create procedure idata()
    begin
      declare i int;
      set i=6;
      while(i<=20)do
        insert into t1 values(i, i, i);
        set i=i+1;
      end while;
    end;;
    delimiter ;
    call idata();

    如果直接使用join语句,MySQL优化器可能会选择表t1或t2作为驱动表,会影响分析SQL语句的执行过程。所以使用straight_join让MySQL使用固定的连接方式执行查询,这样优化器只会按照指定的方式去join。

    走索引的情况:

    通过a字段连接查询:

    explain select * from t2 straight_join t1 on t1.a = t2.a;

    t2作为驱动表,t1作为被驱动表,这条语句的explain结果:

    因为被驱动表t1的字段a有索引,join过程用上了这个索引,因此这个语句的执行流程是这样的:

    1. 从表t2中读入一行数据 R;

    2. 从数据行R中,取出a字段到表t1里去查找;

    3. 取出表t1中满足条件的行,跟R组成一行,作为结果集的一部分;

    4. 重复执行步骤1到3,直到表t2的末尾循环结束。

    这个过程称之为Index Nested-Loop Join

    在这个流程中,扫描t2表5行、之后根据t2.a去表t1中查找,走的是树搜索过程、因此每次扫描一行,总扫描行数为10行。

    不走索引的情况

    我们再用b字段关联查询

    explain select * from t2  straight_join t1 on t1.b = t2.b;

    explain结果如下:

    由于表t1的字段b上没有索引,所以每次都要把t1表中的每一行,拿出来进行对比, mysql采用的是Block Nested-Loop Join,Extra可以看到。该算法并没有将表t1全表扫描20次,它的执行流程为:

    1. 把表t2的数据读入线程内存join_buffer中,由于这个语句中写的是select *,因此是把整个表t2放入了内存;

    2. 扫描表t1,把表t1中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回。

    在这个过程中,对表t1和t2都做了一次全表扫描,因此总扫描次数为25,由于join_buffer是以无序数组的方式组织的,因此对表t1中的每一行,都要做20次判断,总共需要在内存中做的判断次数是:20*5=100次。

    因为使用到了join_buffer,而join_buffer大小是有限的,由join_buffer_size设定,默认为256k。如果一次放不下t2中的所有字段,就会采用分段放的策略,执行策略如下:

    1. 假如t2表足够大,扫描表t2,顺序读取数据行放入join_buffer中,放完第n行join_buffer满了,继续第2步;

    2. 扫描表t1,把t1中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回;

    3. 清空join_buffer;

    4. 继续扫描表t2,顺序读取最后的m行数据放入join_buffer中,继续执行第2步。

    因此表t1可能会被扫描多次,在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与join的各个字段的总数据量数据量小的那个表,就是“小表”,应该作为驱动表

    三个结论:

    1. 如果可以使用被驱动表的索引,join语句还是有其优势的;

    2. 不能使用被驱动表的索引,只能使用Block Nested-Loop Join算法,这样的语句就尽量不要使用;

    3. 在使用join的时候,应该让小表做驱动表。

  • 相关阅读:
    数据结构之队列
    数据结构之循环链表-c语言实现
    数据结构之栈-c语言实现
    数据结构之栈
    vue v-model原理实现
    vue中使用mixins
    async和await
    vue组件中使用watch响应数据
    vue组件中使用<transition></transition>标签过渡动画
    react-motion 动画案例介绍
  • 原文地址:https://www.cnblogs.com/jiezai/p/14249335.html
Copyright © 2011-2022 走看看