mysql数据库多地址表联合查询吗_你了解MySQL中的多表联合查询吗?

前言:

多表联合查询,其实就是我们MySQL中的join语句,经常会看到有人说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 procedureidata;

delimiter ;;create procedureidata()begin

declare i int;set i=1;while(i<=1000)doinsert into t2 values(i, i, i);set i=i+1;end while;end;;

delimiter ;

call idata();create table t1 liket2;insert into t1 (select * from t2 where id<=100)

上述SQL创建了2个表,两张表都有主键索引id,普通索引a。存储过程是往表t2里插入1000行数据,在表t1里插入的是100行数据。

如果直接使用join语句,优化器可能会选择表t1或者表t2作为驱动表,这样会影响分析SQL执行过程。所以为了分析执行过程中的性能问题,我们可以使用straight_join让MySQL使用固定的连接方式查询,下述语句就是让t1作为驱动表,t2作为被驱动表。

select * from t1 straight_join t2 on (t1.a =t2.a);

我们通过explain来看一下这条语句的执行结果。

1e73f115947b8c19f9d30941177ed419.png

B1415936382D47129F69FA64A75982B4

这里可以看出,在这条语句汇总,被驱动表t2字段a上有索引,join过程用上了这个索引,该语句的执行流程如下;

从表t1中读取一行数据R

从数据行R中,取出a字段到表t2里去查找

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

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

上述的过程和我们写程序时的循环查找类似,并且可以使用被驱动表中的索引

在这个流程里,对驱动表t1做了全表扫描,这个过程扫描了1000行数据。由于被驱动表使用了索引,我们构造的数据都是11对应的,所以每次只扫描1行数据,总扫描也是100行,扫描总行数为200

如果不使用join会怎样呢?

如果不使用join,那么我们需要将t1的数据全部取出,然后取出a的值,记为$R.a在执行select * from t2 where a= $R.a,再讲结果和R构成结果集的一行。

这样做虽然也是扫描了100行数据,但是总共执行了101条语句,与MySQL服务器多了100次交互,而且还需要自己去构建结果集。这么做显然没有直接join要好。

Simple-Nested-Loop join

在上述SQL执行的过程中,驱动表走的是全表扫描,被驱动表走的是数搜索,所以整个过程的时间复杂度可以近似表示为:O(n*log2m),所以我们应该尽量使用小表来做驱动表

当n扩大1000倍的时候,时间复杂度扩大1000倍,m扩大1000倍的时候,这个数值只扩大10不到10倍。

结论:

使用join语句,性能比强拆成多个单表执行SQL语句的性能要好

如果使用join语句的话,需要让小表做驱动表

当然,这个结论是建立在“可以使用被驱动表的索引”的前提下的。

Block Nested-Loop Join:

这个时候,按照我们上面的分析,会不会取笛卡尔积,扫描100*1000次呢?我们可以使用explain来查看一下下面的SQL执行结果:

select * from t1 straight_join t2 on (t1.a=t2.b);

de9b4a4d0bb0748d6e551ab17a57f4de.png

95E8FEEC05E3483A8DB48AACEB685542

可以看到这里采用了一种Block Nested-Loop Join的算法。

具体的运算流程是这样的:

把表t1的数据读入到线程内存join_buffer中,由于我们这个语句中写的是select * 因此会讲整个表t1放入内存。

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

我们可以看到,该算法的计算次数是:100*1000=10万次。但是Block Nested-Loop Join虽然在时间复杂度上和Simple-Nested-Loop join算法一致,但是由于是内存计算,所以速度上会快很多,性能也更好。

这里还是应该选择小表作为驱动表,因为如果驱动表太大,那么就需要将驱动表分段载入内存,将驱动表分成多少段,那么就需要扫描被驱动表多少次。所以这里还是推荐使用小表作为的驱动表。

结论:

如果可以使用被驱动表的索引,join语句非常有优势

不能使用被驱动表的索引,只能使用Block Nested-Loop Join算法,尽量不要使用

在使用join的时候,应选择小表作为驱动表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值