8.4.4 How MySQL Uses Internal Temporary Tables

这是MySQL手册中的一节,尝试补充了一些解释。用的版本是MySQL5.6.15社区版

In some cases, the server creates internal temporary tables while processing queries. Such a table can be held in memory and processed by the MEMORY storage engine, or stored on disk and processed by the MyISAM storage engine. The server may create a temporary table initially as an in-memory table, then convert it to an on-disk table if it becomes too large. Users have no direct control over when the server creates an internal temporary table or which storage engine the server uses to manage it.

Temporary tables can be created under conditions such as these:

  • UNION queries use temporary tables.
    union all,顺序把各select的所有记录写入一个临时表,都写完了,再查出来发送给客户端;
    union,与上面类似,不同的是,临时表是有唯一键的,重复数据只记录一条;
  • Some views require temporary tables, such those evaluated using the TEMPTABLE algorithm, or that use UNION or aggregation.
  • If there is an ORDER BY clause and a different GROUP BY clause, or if the ORDER BY or GROUP BY contains columns from tables other than the first table in the join queue, a temporary table is created.
    即使只有一个group by,如果用不上索引,也会需要临时表;此时临时表有一个唯一键,即group by的列;还保存有select的列,包括聚合函数的列,比如sum的值;
    如果order by时出现filesort,此时不一定有临时表;filesort有单独的排序区sort buffer,和临时文件保存排序数据,数据量大时,会保存在硬盘;filesort和临时表不是一个概念,没有必然联系;
    mysql> show create table three\G
    *************************** 1. row ***************************
    Table: three
    Create Table: CREATE TABLE `three` (
    `id3` int(11) DEFAULT NULL,
    `name3` varchar(10) DEFAULT NULL,
    `age` tinyint(4) DEFAULT NULL,
    KEY `i_id3` (`id3`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)mysql> explain select avg(age),name3 from three group by name3;
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                           |
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    |  1 | SIMPLE      | three | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using temporary; Using filesort |
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    1 row in set (0.08 sec)

    mysql> explain select avg(age),name3 from three group by name3 order by null;
    +—-+————-+——-+——+—————+——+———+——+——+—————–+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra           |
    +—-+————-+——-+——+—————+——+———+——+——+—————–+
    |  1 | SIMPLE      | three | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using temporary |
    +—-+————-+——-+——+—————+——+———+——+——+—————–+
    1 row in set (0.00 sec)

    mysql> explain select avg(age),name3 from three group by name3 order by age;
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                           |
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    |  1 | SIMPLE      | three | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using temporary; Using filesort |
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    1 row in set (0.00 sec)

    mysql> explain select avg(age) avgage,name3 from three group by name3 order by avgage;
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                           |
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    |  1 | SIMPLE      | three | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using temporary; Using filesort |
    +—-+————-+——-+——+—————+——+———+——+——+———————————+
    1 row in set (0.02 sec)
    只要group by用不上索引,就需要临时表来解决去重和计算聚合函数;
    加上索引,执行计划就有所变化了:
    mysql> alter table three add key i_name3(name3);
    Query OK, 0 rows affected (0.51 sec)
    Records: 0  Duplicates: 0  Warnings: 0

    mysql> show create table three\G
    *************************** 1. row ***************************
    Table: three
    Create Table: CREATE TABLE `three` (
    `id3` int(11) DEFAULT NULL,
    `name3` varchar(10) DEFAULT NULL,
    `age` tinyint(4) DEFAULT NULL,
    KEY `i_id3` (`id3`),
    KEY `i_name3` (`name3`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)

    mysql> explain select avg(age),name3 from three group by name3;
    +—-+————-+——-+——-+—————+———+———+——+——+——-+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra |
    +—-+————-+——-+——-+—————+———+———+——+——+——-+
    |  1 | SIMPLE      | three | index | i_name3       | i_name3 | 13      | NULL |    7 | NULL  |
    +—-+————-+——-+——-+—————+———+———+——+——+——-+
    1 row in set (0.00 sec)

    上面这个SQL用到了索引,利用innodb b+tree的特性,按顺序读取name3的值,并计算其聚合函数;当读取的name3的值发生变化时,就表示变化发生前的那个name3的值对应的聚合函数值计算完了,发送给网络接口;由此就不需要用临时表来去掉name3重复值,以及计算聚合函数值了;
    下面这个SQL也用到了索引,但是按照聚合函数值排序,就比上面多了临时表和filesort;
    mysql> explain select avg(age) avgage,name3 from three group by name3 order by avgage;
    +—-+————-+——-+——-+—————+———+———+——+——+———————————+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                           |
    +—-+————-+——-+——-+—————+———+———+——+——+———————————+
    |  1 | SIMPLE      | three | index | i_name3       | i_name3 | 13      | NULL |    7 | Using temporary; Using filesort |
    +—-+————-+——-+——-+—————+———+———+——+——+———————————+
    1 row in set (0.04 sec)
    上面这个SQL,group by使用了索引。利用索引的顺序读取name3,并计算avg(age),算好一个avgage值之后,把该avgage和name3写入临时表;
    都写完之后,从临时表读取数据,按avgage排序,然后发送结果;
    而group by与order by的列不属于同一个表时,只是多了个join过程,其他过程应该是同理的;

  • DISTINCT combined with ORDER BY may require a temporary table.
    distinct与group by同理
    mysql> show create table three\G
    *************************** 1. row ***************************
    Table: three
    Create Table: CREATE TABLE `three` (
    `id3` int(11) DEFAULT NULL,
    `name3` varchar(10) DEFAULT NULL,
    `age` tinyint(4) DEFAULT NULL,
    KEY `i_id3` (`id3`),
    KEY `i_name3` (`name3`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)mysql> explain select distinct(age) from three;
    +—-+————-+——-+——+—————+——+———+——+——+—————–+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra           |
    +—-+————-+——-+——+—————+——+———+——+——+—————–+
    |  1 | SIMPLE      | three | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using temporary |
    +—-+————-+——-+——+—————+——+———+——+——+—————–+
    1 row in set (0.01 sec)

    mysql> explain select distinct(name3) from three;
    +—-+————-+——-+——-+—————+———+———+——+——+————-+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
    +—-+————-+——-+——-+—————+———+———+——+——+————-+
    |  1 | SIMPLE      | three | index | i_name3       | i_name3 | 13      | NULL |    7 | Using index |
    +—-+————-+——-+——-+—————+———+———+——+——+————-+
    1 row in set (0.04 sec)

     
  • If you use the SQL_SMALL_RESULT option, MySQL uses an in-memory temporary table, unless the query also contains elements (described later) that require on-disk storage.
  • Derived tables (subqueries in the FROM clause).
    mysql> show create table one\G
    *************************** 1. row ***************************
    Table: one
    Create Table: CREATE TABLE `one` (
    `id` int(11) DEFAULT NULL,
    `name` varchar(10) DEFAULT NULL,
    KEY `i_name` (`name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.04 sec)mysql> explain select * from (select * from one) a;
    +—-+————-+————+——+—————+——+———+——+——+——-+
    | id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows | Extra |
    +—-+————-+————+——+—————+——+———+——+——+——-+
    |  1 | PRIMARY     | <derived2> | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
    |  2 | DERIVED     | one        | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
    +—-+————-+————+——+—————+——+———+——+——+——-+
    2 rows in set (0.00 sec)
    在执行计划里叫DERIVED,实现上就是一个临时表;
    上面SQL把one的所有记录写入临时表,然后再查出来;
  • Tables created for subquery or semi-join materialization.
    想用in看一下子查询,结果被优化成join了;
    mysql> explain select * from one where id in(select id2 from two);
    +—-+————-+——-+——+—————+——-+———+—————+——+——————————+
    | id | select_type | table | type | possible_keys | key   | key_len | ref           | rows | Extra                        |
    +—-+————-+——-+——+—————+——-+———+—————+——+——————————+
    |  1 | SIMPLE      | one   | ALL  | NULL          | NULL  | NULL    | NULL          |    2 | Using where                  |
    |  1 | SIMPLE      | two   | ref  | i_id2         | i_id2 | 5       | testdb.one.id |    1 | Using index; FirstMatch(one) |
    +—-+————-+——-+——+—————+——-+———+—————+——+——————————+
    2 rows in set (0.00 sec)
    5.6加了个firstmatch的优化,而且把subquery变成join了,效率提高不少;mysql> explain select * from one where exists (select id2 from two where one.id=two.id2);
    +—-+——————–+——-+——+—————+——-+———+—————+——+————-+
    | id | select_type        | table | type | possible_keys | key   | key_len | ref           | rows | Extra       |
    +—-+——————–+——-+——+—————+——-+———+—————+——+————-+
    |  1 | PRIMARY            | one   | ALL  | NULL          | NULL  | NULL    | NULL          |    2 | Using where |
    |  2 | DEPENDENT SUBQUERY | two   | ref  | i_id2         | i_id2 | 5       | testdb.one.id |    1 | Using index |
    +—-+——————–+——-+——+—————+——-+———+—————+——+————-+
    2 rows in set (0.04 sec)
    mysql> explain select * from one where exists (select id2 from two where one.id=two.id2) order by name;
    +—-+——————–+——-+——+—————+——-+———+—————+——+—————————–+
    | id | select_type        | table | type | possible_keys | key   | key_len | ref           | rows | Extra                       |
    +—-+——————–+——-+——+—————+——-+———+—————+——+—————————–+
    |  1 | PRIMARY            | one   | ALL  | NULL          | NULL  | NULL    | NULL          |    2 | Using where; Using filesort |
    |  2 | DEPENDENT SUBQUERY | two   | ref  | i_id2         | i_id2 | 5       | testdb.one.id |    1 | Using index                 |
    +—-+——————–+——-+——+—————+——-+———+—————+——+—————————–+
    2 rows in set (0.00 sec)
    上面这两个SQL都没有用到临时表;
    子查询用到临时表的情况需要再观察;
    semijoin的目前还不懂,后面再说了;

To determine whether a query requires a temporary table, use EXPLAIN and check the Extra column to see whether it says Using temporary (see Section 8.8.1, “Optimizing Queries with EXPLAIN”). EXPLAIN will not necessarily say Using temporary for derived or materialized temporary tables.

If an internal temporary table is created initially as an in-memory table but becomes too large, MySQL automatically converts it to an on-disk table. The maximum size for in-memory temporary tables is the minimum of the tmp_table_size and max_heap_table_size values. This differs from MEMORY tables explicitly created withCREATE TABLE: For such tables, only the max_heap_table_size system variable determines how large the table is permitted to grow and there is no conversion to on-disk format.

When the server creates an internal temporary table (either in memory or on disk), it increments theCreated_tmp_tables status variable. If the server creates the table on disk (either initially or by converting an in-memory table) it increments the Created_tmp_disk_tables status variable.

Some conditions prevent the use of an in-memory temporary table, in which case the server uses an on-disk table instead:

  • Presence of a BLOB or TEXT column in the table
  • Presence of any string column in a GROUP BY or DISTINCT clause larger than 512 bytes for binary strings or 512 characters for nonbinary strings. (Before MySQL 5.6.15, the limit is 512 bytes regardless of string type.)
  • Presence of any string column with a maximum length larger than 512 (bytes for binary strings, characters for nonbinary strings) in the SELECT list, if UNION or UNION ALL is used

简单地说,临时表是用来以表的形式保存中间结果的。数据少时是heap表,在内存中,数据多时是MyISAM表,在硬盘上。

注意,不是所有的中间结果都用临时表。filesort保存中间结果用的临时文件,不是临时表。

Internal Temporary Tables的更多相关文章

  1. HOW MYSQL USES INTERNAL TEMPORARY TABLES

    HOW MYSQL USES INTERNAL TEMPORARY TABLES Table of Contents [hide] 1)UNION queries 2)Some views 3)SQL ...

  2. Temporary Tables and the TableType Property [AX 2012]

    Temporary Tables and the TableType Property [AX 2012] 1 out of 1 rated this helpful - Rate this topi ...

  3. Part 17 Temporary tables in SQL Server

    Temporary tables in SQL Server

  4. Temporary Tables临时表

    1简介 ORACLE数据库除了可以保存永久表外,还可以建立临时表temporary tables.这些临时表用来保存一个会话SESSION的数据, 或者保存在一个事务中需要的数据.当会话退出或者用户提 ...

  5. T-SQL Recipes之 Table Variables and Temporary Tables

    Problem 许多时候, 我们想要Table Variables在动态SQL中执行,但现实是很骨感的.比如这个示例: DECLARE @sql_command NVARCHAR(MAX); DECL ...

  6. 【mysql】关于临时表

    mysql官方的介绍 In some cases, the server creates internal temporary tables while processing queries. Suc ...

  7. Don’t Assume – Per Session Buffers

    MySQL has a number of global buffers, i.e. your SGA. There are also a number of per session/thread b ...

  8. open_table与opened_table

    好多人在调优Mysql的时候,总是对open_tables和opend_tables两个参数分别不清. 网上好多解释都是这样的:open_tables:当前打开表的数量opened_tables:当前 ...

  9. 【MySQL】查询使用临时表

    MySQL查询产生临时表的分析 官网说明的地址:http://dev.mysql.com/doc/refman/5.5/en/internal-temporary-tables.html 参考:htt ...

随机推荐

  1. bzoj 3209 花神的数论题 —— 数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3209 算是挺简单的数位DP吧,但还是花了好久才弄明白... 又参考了博客:https://b ...

  2. C# Event.ClickCount 解决垃圾鼠标带来的烦恼

    今天调试遇到个Bug,百思不得其解的是在自己的设备上重来不重现,在测试机上百分百重现,如下: 问题:点击一次Button执行两次Click操作 分析:看Log的确是执行了两次,就像真的点击了两次But ...

  3. 洛谷P2756 飞行员配对方案问题(二分图匹配)

    P2756 飞行员配对方案问题 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其 ...

  4. Gym - 101981K The 2018 ICPC Asia Nanjing Regional Contest K.Kangaroo Puzzle 暴力或随机

    题面 题意:给你1个20*20的格子图,有的是障碍有的是怪,你可以每次指定上下左右的方向,然后所有怪都会向那个方向走, 如果2个怪撞上了,就融合在一起,让你给不超过5w步,让所有怪都融合 题解:我们可 ...

  5. Django 安装步骤

    Django的安装和简单使用 -安装: pip3 install django==1.11.9 pycharm 下安装,选择版本号, -使用: 命令创建项目:django-admin startpro ...

  6. vue ssr 项目改造经历

    vue ssr 项目改造经历 由于工作项目需求,需要将原有的项目改造,vue ssr 没有用到nuxt,因为vue ssr更利于seo,没办法,一个小白的改造经历, 首先说明一下,小白可以借鉴,高手也 ...

  7. 阿里云 CentOS 6.5 使用XAMPP 搭建LAMP环境

    LAMP环境是常见的服务器环境,也是PHP网站常用的服务器环境,很多人喜欢手动配置,但是手动配置LAMP复杂.麻烦,简单一点的话可以使用集成环境.试了下LNMP的集成环境,用不习惯,另外由于本地一直使 ...

  8. Phoenix与Squirrel 是什么?

    不多说,直接上干货! 前言 Phoenix是HBase的开源SQL引擎. squirrel是windows上Phoneix可视化工具.  Phoenix的官网 http://phoenix.apach ...

  9. 5.23Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分

    作者:https://www.cnblogs.com/lyjin/p/6389349.html PO:持久对象(persistent object):---po就是在Object/Relation M ...

  10. HEK_费用报表审核无审核权限,有些字段无法编辑的问题处理

    Q:HEK_费用报表审核无审核权限,有些字段无法编辑的问题处理 A:设置AP员工->给AP员工分配审批权限->绑定员工和ERP账号 1.将审核人设置为AP员工 2.分配给员工审批权限 3. ...