You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
create table t1(id int primary key, a int, b int, index(a));
delimiter ;;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=1000)do
insert into t1 values(i, i, i);
set i=i+1;
end while;
end;;
delimiter ;
call idata();
union 的执行
(select 1000 as f) union (select id from t1 order by id desc limit 2);
下图为该语句的 explain 结果
可以看到:
第二行 key = PRIMARY,说明第二个子句用到了索引 id
第三行 Extra 字段,表示在对子查询的结果集做 union 的时候,使用了临时表(Using temporary)
示例表
union 的执行
下图为该语句的 explain 结果
可以看到:
这个语句的执行流程如下:
流程图如下:
这里的内存临时表起到了暂存数据的作用,而且计算过程还用上了临时表主键 id 的唯一性约束,实现了 union 的语义
如果 union 改成 union all 的话,就没有了去重的语义,这样执行的时候也就用不到临时表了,查询的结果直接作为结果集的一部分了
group by 的执行
下图为该语句的 explain 结果
可以看到:
这个语句的执行流程如下:
流程图如下:
如果不需要排序,可以使用 order by null,直接从临时表取数据返回
内存临时表的大小是有限制的,由参数 tmp_table_size 控制,默认为 16 M,如果内存临时表大小到达了上限,这时候会把内存临时表转换成磁盘临时表,磁盘临时表默认使用 InnoDB
group by 优化方法----索引
group by 的语义逻辑是统计不同的值出现的个数,但是由于每一行 id % 100 的结果是无序的,所以就需要一个临时表,来记录并统计结果
如果可以保证出现的数据是有序的,就可以避免临时表的使用
执行过程:
按照这个逻辑,扫描到数据结束就可以直接拿到 group by 的结果,不再需要临时表
在 MySQL 5.7 版本支持了 generated column 机制,用来实现列数据的关联更新。如果是 MySQL 5.6 及之前的版本,可以创建普通列和索引来解决这个问题
group by 语句可以改为:
explain 的结果:
group by 优化方法----直接排序
可以在 group by 语句中加入 SQL_BIG_RESULT 这个提示(hint),告诉优化器这个语句涉及的数据量很大,直接用磁盘临时表,这样就省去了放入内存临时表的步骤
执行流程:
执行流程图:
explain 结果:
总结
The text was updated successfully, but these errors were encountered: