文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

MySQL Internal Temporary

2024-04-02 19:55

关注

什么是Internal Temporary?

临时表分为两种,一种是当执行一些SQL的时候MySQL会自动创建的一些中间结果集,称为internal temporary,这些中间结果集可能放在memory中,也有可能放在disk上;

还有一种是手动执行create temporary table 语法生成的外部临时表,这种临时表存储在memory上,数据库shutdown,就会自动删除;

本篇讲的临时表都是指内部临时表,测试使用的MySQL版本是8.0.13;


怎么判断有没有使用内部临时表?

执行计划explain或explain format=json 中出现using temporary;

show status中Created_tmp_disk_tables或Created_tmp_tables数值增加;


什么情况下产生Internal temporary table?

(1)除了后面提到的特殊情况,所有使用union的SQL,但是使用union all没有使用临时表

(2)用到TEMPTABLE算法或者是UNION查询中的视图

mysql> desc select * from t_order union select * from t_group;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type  | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | PRIMARY      | t_order    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL            |
|  2 | UNION        | t_group    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL            |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
3 rows in set, 1 warning (0.01 sec)
但是使用union all没有使用临时表
mysql> desc select * from t_order union all select * from t_group;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | PRIMARY     | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL  |
|  2 | UNION       | t_group | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
2 rows in set, 1 warning (0.00 sec)

(3)使用衍生表

(4)子查询和semi-join

mysql> desc select  * from (select * from t_order)t;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL  |
|  2 | DERIVED     | t_order    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
2 rows in set, 1 warning (0.01 sec)
mysql> desc format=json  select  * from (select * from t_order)t;
......
      "materialized_from_subquery": {
        "using_temporary_table": true,

(5)order by和group by的子句不一样时,或者表连接中order by或group by的列是被驱动表中的列;

order by和group by 同时使用的时候:

mysql> desc select dept_no from t_order group by dept_no order by dept_no;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                           |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
|  1 | SIMPLE      | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | Using temporary; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)
或者:
mysql> set session sql_mode='';
Query OK, 0 rows affected (0.00 sec)
mysql> desc select dept_no from t_order group by dept_no order by emp_no;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                           |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
|  1 | SIMPLE      | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | Using temporary; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)

order by 和group by 分别和join使用的时候:

mysql> desc select * from t_group t1 join t_order t2 on t1.emp_no=t2.emp_no order by t2.emp_no;
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+---------------------------------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref                 | rows | filtered | Extra                           |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+---------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL  | NULL    | NULL                |   10 |   100.00 | Using temporary; Using filesort |
|  1 | SIMPLE      | t2    | NULL       | ref  | ix_t1         | ix_t1 | 5       | employees.t1.emp_no |    1 |   100.00 | NULL                            |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+---------------------------------+
2 rows in set, 1 warning (0.00 sec)
mysql> desc select * from t_group t1 join t_order t2 on t1.emp_no=t2.emp_no order by t1.emp_no;
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref                 | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+----------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL  | NULL    | NULL                |   10 |   100.00 | Using filesort |
|  1 | SIMPLE      | t2    | NULL       | ref  | ix_t1         | ix_t1 | 5       | employees.t1.emp_no |    1 |   100.00 | NULL           |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+----------------+
2 rows in set, 1 warning (0.00 sec)
mysql> desc select t1.dept_no from t_group t1 join t_order t2 on t1.emp_no=t2.emp_no group by t1.dept_no;
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref                 | rows | filtered | Extra           |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+-----------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL  | NULL    | NULL                |   10 |   100.00 | Using temporary |
|  1 | SIMPLE      | t2    | NULL       | ref  | ix_t1         | ix_t1 | 5       | employees.t1.emp_no |    1 |   100.00 | Using index     |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+-----------------+
2 rows in set, 1 warning (0.00 sec)
mysql> desc  select t2.dept_no from t_group t1 join t_order t2 on t1.emp_no=t2.emp_no group by t2.dept_no;
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref                 | rows | filtered | Extra           |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+-----------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL  | NULL    | NULL                |   10 |   100.00 | Using temporary |
|  1 | SIMPLE      | t2    | NULL       | ref  | ix_t1         | ix_t1 | 5       | employees.t1.emp_no |    1 |   100.00 | NULL            |
+----+-------------+-------+------------+------+---------------+-------+---------+---------------------+------+----------+-----------------+
2 rows in set, 1 warning (0.00 sec)

(6)使用distinct或者distinct集合ORDER BY时

mysql> desc select distinct * from t_order;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | SIMPLE      | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | Using temporary |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------+
1 row in set, 1 warning (0.00 sec)

(7)SQL中用到SQL_SMALL_RESULT选项时;

(8)INSERT ... SELECT针对同一个表操作的时候

mysql> desc insert into t_order select * from t_order;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | INSERT      | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | NULL            |
|  1 | SIMPLE      | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | Using temporary |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------+
2 rows in set, 1 warning (0.00 sec)

(9)使用GROUP_CONCAT() or COUNT(DISTINCT)

使用group_concat()时产生临时表:

mysql> flush status;
Query OK, 0 rows affected (0.02 sec)
mysql> select dept_no,group_concat(emp_no) from t_order group by dept_no;
+---------+-------------------------+
| dept_no | group_concat(emp_no)    |
+---------+-------------------------+
| d002    | 31112                   |
| d004    | 10004                   |
| d005    | 24007,30970,40983,50449 |
| d006    | 22744                   |
| d007    | 49667                   |
| d008    | 48317                   |
+---------+-------------------------+
6 rows in set (0.00 sec)
mysql> show status like '%tmp%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0     |
| Created_tmp_files       | 0     |
| Created_tmp_tables      | 1     |
+-------------------------+-------+
3 rows in set (0.00 sec)

使用count(distinct)时产生临时表:

mysql> flush status;
Query OK, 0 rows affected (0.02 sec)
mysql> desc select count(distinct dept_no) from t_order;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   10 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> show status like '%tmp%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0     |
| Created_tmp_files       | 0     |
| Created_tmp_tables      | 1     |
+-------------------------+-------+
3 rows in set (0.01 sec)

什么情况下产生的内部临时表不是在内存中,而是在磁盘上?

(1)表存在blob或text字段;

(2)在SELECT   UNION、UNION ALL查询中,存在最大长度超过512的列(对于字符串类型是512个字符,对于二进制类型则是512字节);

(3)使用show columns和describe命令在存在blob列的表上;


内部临时表使用什么存储引擎?

MySQL8.0.2开始支持internal_tmp_mem_storage_engine参数;

(1)当internal_tmp_mem_storage_engine=TempTable时,

TempTable存储引擎为varchar和varbinary数据类型提供高效的存储,temptable_max_ram=1G定义临时表最大可以使用的内存空间,但是如果参数temptable_use_mma=on,则表示可以继续使用内存存储临时表,如果off,则临时表超过阈值,只能使用磁盘存储;

(2)当internal_tmp_mem_storage_engine=memory时:

内部临时表大小超过参数tmp_table_size和max_heap_table_size时候,会自动从内存中转移到磁盘上,内部临时表在磁盘上默认使用的是innodb存储引擎,由参数internal_tmp_disk_storage_engine决定.


参考链接

Internal Temporary Table Use in MySQL


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯