• 对于join操作,MySQL它是咋做的?


      首先我们对于join操作,需要了解两个概念:驱动表和被驱动表。首先先给出两张表:

    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;
    
    drop procedure idata;
    delimiter ;;
    create procedure idata()
    begin
      declare i int;
      set i=1;
      while(i<=1000)do
        insert into t2 values(i, i, i);
        set i=i+1;
      end while;
    end;;
    delimiter ;
    call idata();
    
    create table t1 like t2;
    insert into t1 (select * from t2 where id<=100)

    t1数据100行,t2数据1000行,a字段有索引,b字段无索引。

    select * from t1 straight_join t2 on (t1.a=t2.a);// 在执行该sql时,t1被强制性作为驱动表,而t2就是被驱动表了

      这条语句执行过程是先对t1全表扫,拿到每一行数据的a值,然后作为搜索条件到t2表里进行搜索,以为b有索引并且b的值不重复,所以认为扫表(回表)次数就是100+1000(因为走索引很快并且只要找到对应的t2的a之后只需要回表一次),ok,扫表次数:N+M。

      之后再看复杂度,首先t1的扫表次数是N,其次每一个t1的行在t2里都需要做两次索引查找操作,可以认为是N*2*logM,因此复杂度为:N+N*2*logM。

      由此可见,当小表作为驱动表时,复杂度会小很多!但是这是在被驱动表t2的a值有索引的情况下,如果没有索引,t2就只能全表扫描了,这种情况下建议立马考虑索引问题,虽然说mysql对此有它自己的优化方案:Block Nested Loop

      我们可以再看一看对于驱动表没有索引的情况下再采用上面的方式,扫表次数以及判断复杂度的不同:

      (1)扫表:t1还是继续他的N次扫表,然后t2就大有不同了,因为缺少了索引,导致只能走全表扫描也就是M次,那也就是相当暴力的N+N*M次扫表,这个时候不论大表做驱动还是小表做驱动,扫表次数都一样。。。

      (2)数据判断复杂度:t2直接全表扫,N+N*M。。

      通过上面的判断,发现做法“惊为天人”!于是乎,mysql是这样来优化的,在扫描行数上,驱动表因为一般是小表,可以一次性加载到内存中,然后把判断值的操作放到内存中执行(有索引的话,判断操作是在磁盘里走索引判断),也就是说每次都做t2的全表扫,然后这些M和每一个t1的值做匹配,也就是在扫表次数上比上一个要好很多:N+M,但是在判断的时间复杂度来看,其实还是N*M,但是由于是在内存操作,所以在时间上会弥补很多!!但是由于join_buffer的大小有限制,所以很多时候t1的数据不能一次性加载进来,所以在这个操作过程中t2表可能会被扫好几次,这个是由t1要加载到buffer几次而决定,加载的越多,t2的扫表次数越多,所以buffer的空间越大越好!!

    而有关mysql决定哪些表是否是小表而来做驱动时,有他自己的选择方案:可能有些表的数据很大,但是因为有某些where条件而使得真实加载到buffer的数据很少,mysql也就很有可能选择它做小表,或者说是某些表在select后面的条件很少,例如select t1.*,t2.b  这种,因为t2所需要的数据很少,因此可以剩下更多的buffer空间,减少加载buffer的次数,所以t2也很有可能被当作小表而当作驱动表!!

  • 相关阅读:
    jeos没有消亡,但看 debian 的 netinst .iso格式,那就是jeos的系统!
    ubuntu-14.04.x-desktop-amd64.iso:安装Oracle11gR2
    ubuntu-16.04.1-desktop-amd64.iso:ubuntu-16.04.1-desktop-amd64:安装Oracle11gR2
    JDBC 基础
    How to check for null/empty/whitespace values with a single test?
    STRING DELIMITED BY SIZE
    分行符
    甲醛超标
    notepad++ 去空行
    shell脚本中的set -e和set -o pipefail
  • 原文地址:https://www.cnblogs.com/Booker808-java/p/11658099.html
Copyright © 2020-2023  润新知