在某些情况下,服务器在处理语句时创建内部临时表。用户无法直接控制何时发生这种情况。
服务器在以下条件下创建临时表:
UNION语句的 评估,有一些例外情况将在后面描述。评估某些视图,例如使用
TEMPTABLE算法UNION、 或聚合的视图。派生表的评估(请参阅 第 13.2.10.8 节,“派生表”)。
为子查询或半连接具体化创建的表(请参阅 第 8.2.2 节,“优化子查询、派生表和视图引用”)。
评估包含
ORDER BY子句和不同GROUP BY子句的语句,ORDER BY或GROUP BY包含连接队列中第一个表以外的表的列的语句。DISTINCT结合 评估ORDER BY可能需要一个临时表。对于使用
SQL_SMALL_RESULT修饰符的查询,MySQL 使用内存中的临时表,除非查询还包含需要磁盘存储的元素(稍后描述)。为了评估
INSERT ... SELECT从同一个表中选择并插入到同一个表中的语句,MySQL 创建一个内部临时表来保存来自 的行SELECT,然后将这些行插入到目标表中。请参阅 第 13.2.5.1 节,“INSERT ... SELECT 语句”。多表
UPDATE语句的评估。GROUP_CONCAT()或COUNT(DISTINCT)表达式 的评估。
要确定语句是否需要临时表,请使用
EXPLAIN并检查该
Extra列以查看它是否表示
Using temporary(请参阅
第 8.8.1 节,“使用 EXPLAIN 优化查询”)。EXPLAIN
不一定说Using temporary派生或具体化的临时表。
某些查询条件会阻止使用内存中的临时表,在这种情况下,服务器会改用磁盘上的表:
服务器不会为
UNION满足特定条件的语句使用临时表。相反,它从临时表创建中仅保留执行结果列类型转换所需的数据结构。该表未完全实例化,也没有向其中写入或读取任何行;行直接发送给客户端。结果是减少了内存和磁盘需求,并且第一行发送到客户端之前的延迟更小,因为服务器不需要等到最后一个查询块被执行。EXPLAIN优化器跟踪输出反映了这种执行策略:
UNION RESULT查询块不存在,因为该块对应于从临时表读取的部分。
这些条件有资格在UNION没有临时表的情况下进行评估:
工会是
UNION ALL,不是UNION或UNION DISTINCT。没有全局
ORDER BY条款。联合不是语句的顶级查询块
{INSERT | REPLACE} ... SELECT ...。
内部临时表可以保存在内存中并由存储引擎处理,或者
由MEMORY存储引擎存储在磁盘上。
InnoDBMyISAM
如果内部临时表创建为内存表但变得太大,MySQL 会自动将其转换为磁盘表。内存中临时表的最大大小由
tmp_table_size或
max_heap_table_size值定义,以较小者为准。这不同于使用
MEMORY显式创建的表
CREATE TABLE。对于此类表,只有max_heap_table_size
变量决定了表可以增长到多大,并且没有转换为磁盘格式。
该
internal_tmp_disk_storage_engine
变量定义了服务器用来管理磁盘内部临时表的存储引擎。允许的值为
INNODB(默认值)和
MYISAM.
使用
internal_tmp_disk_storage_engine=INNODB时,生成超过
InnoDB行或列限制的磁盘内部临时表的查询会返回行大小太大或列太多
错误。解决方法是设置
internal_tmp_disk_storage_engine
为MYISAM.
当在内存或磁盘上创建内部临时表时,服务器会递增该
Created_tmp_tables值。在磁盘上创建内部临时表时,服务器会递增该
Created_tmp_disk_tables
值。如果在磁盘上创建了太多的内部临时表,请考虑增加
tmp_table_size和
max_heap_table_size设置。
内存临时表由
MEMORY存储引擎管理,它使用固定长度的行格式。VARCHAR和
VARBINARY列值被填充到最大列长度,实际上将它们存储为
CHAR和BINARY列。
磁盘上的临时表由
存储引擎InnoDB或MyISAM存储引擎管理(取决于
internal_tmp_disk_storage_engine
设置)。两个引擎都使用动态宽度行格式存储临时表。列只占用所需的存储空间,与使用固定长度行的磁盘表相比,这减少了磁盘 I/O、空间需求和处理时间。
对于最初在内存中创建内部临时表,然后将其转换为磁盘表的语句,跳过转换步骤并首先在磁盘上创建表可能会获得更好的性能。该
big_tables变量可用于强制内部临时表的磁盘存储。