读mysql45讲-内存临时表

union执行流程

创建一个表t2,主键id,字段a添加索引,字段b无索引,并且按照递增插入1000条数据,id和a,b都是从1到1000。

然后执行一条sql:

explain select 1000 as f union (select id from t2 order by id desc limit 2)

在这里插入图片描述

这里使用到了union,所以在两个子查询的结果还需要做去重处理,可以看到解析结果是使用了临时表的。
执行流程大概如下:

  1. 创建一个临时表,字段只有f ,并且f是主键字段(为啥是主键字段?因为只有一个?还是因为第一个出现字段?还是因为需要根据这个去重?)
  2. 执行第一个子查询,将1000放入临时表中
  3. 执行第二个子查询,先查询到id=1000,准备放入临时表中,但临时表中已经有了一个1000,违反唯一性约束,放入失败;继续查询id=999可以放入临时表中
  4. 从临时表中取出所有数据,返回结果,也就是1000和999,删除临时表。

把上面的查询语句修改一下:

explain select 1000 as f union on (select id from t2 order by id desc limit 2)

把union 改成了 union all,也就是不需要去重了,没有了对数据的进一步处理:

在这里插入图片描述

可以看到这里就没有使用到临时表,因为没有对查询结果的进一步处理,直接就可以返回结果。

group by 执行流程

执行一条sql语句:

explain
select
	id%10 as m,
	count(1) as c
from
	t2
group by
	m

在这里插入图片描述

执行结果分析中看到是使用了覆盖索引和临时表的。执行流程大概如下:

  1. 创建临时表,有两个字段,一个m,一个c(也就是select字段中取得别名)
  2. 扫描表索引字段a,不需要回表就可以直接取得主键id字段的值,计算i%10,得到结果x,将结果放入临时表,如果临时表中没有m列的值等于x的,就插入一条记录(x,1);如果x已经存在了,就将c列的值加上一。

修改一下sql语句:

explain
select
	id%10 as m,
	count(1) as c
from
	t2
group by
	id

在这里插入图片描述

执行结果中就不会使用临时表,区别就是使用了索引字段,如果将上面sql的id字段都换成b字段,会发现执行结果分析就会有临时表。
临时表的大小是通过参数tmp_table_size来控制的。

如果group by字段中没有索引,而且放入到临时表的数据量很大,超过了临时表大小的限制,就会转为磁盘临时表。
如果事先知道数据量很大,可以直接指定使用磁盘临时表;

修改一下sql:

explain
select
	sql_BIG_RESULT b%10 as m,
	count(1) as c
from
	t2
group by
	b

在这里插入图片描述

可以看到执行结果分析中只使用了排序,没有使用临时表。group by 有索引的字段和group by 无索引的字段的区别就是数据是否是排序过的,如果排序过的,对于上面sql出现的count(1)函数就可以直接统计出现的次数,而不需要去出现一次计数一个。

MySQL什么时候会使用内部临时表?

  1. 如果语句执行过程可以一边读数据,一边直接得到结果,是不需要额外内存的,否则就需要额外的内存,来保存中间结果;
  2. 如果执行逻辑需要用到二维表特性,就会优先考虑使用临时表。比如union 需要用到唯一索引约束, group by还需要用到另外一个字段来存累积计数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值