在某些情况下,服务器在处理语句时创建内部临时表。用户无法直接控制何时发生这种情况。
服务器在以下情况下创建临时表:
-
评估
UNION
语句,除非有后面描述的例外情况。 -
评估某些视图,例如使用
TEMPTABLE
算法、UNION
或聚合。 -
评估派生表(见 第 15.2.15.8 节,“派生表”)。
-
评估公共表表达式(见 第 15.2.20 节,“WITH(公共表表达式)”)。
-
为子查询或半连接物化创建的表(见 第 10.2.2 节,“优化子查询、派生表、视图引用和公共表表达式”)。
-
评估包含
ORDER BY
子句和不同的GROUP BY
子句的语句,或者评估ORDER BY
或GROUP BY
中包含来自连接队列中第一个表以外的列的语句。 -
评估
DISTINCT
结合ORDER BY
可能需要临时表。 -
对于使用
SQL_SMALL_RESULT
修饰符的查询,MySQL 使用内存临时表,除非查询也包含需要磁盘存储的元素(后面描述)。 -
为了评估
INSERT ... SELECT
语句,从同一个表中选择和插入,MySQL 创建一个内部临时表来保存SELECT
的行,然后将这些行插入目标表。见 第 15.2.7.1 节,“INSERT ... SELECT 语句”。 -
评估多表
UPDATE
语句。 -
评估
GROUP_CONCAT()
或COUNT(DISTINCT)
表达式。 -
评估窗口函数(见 第 14.20 节,“窗口函数”) 使用临时表如有必要。
要确定语句是否需要临时表,请使用 EXPLAIN
并检查 Extra
列,以查看是否说 Using temporary
(见 第 10.8.1 节,“使用 EXPLAIN 优化查询”)。 EXPLAIN
不一定说 Using temporary
对于派生或物化临时表。对于使用窗口函数的语句,EXPLAIN
with FORMAT=JSON
始终提供窗口步骤信息。如果窗口函数使用临时表,则在每个步骤中都将其指示。
某些查询条件会阻止使用内存临时表,在这种情况下,服务器将使用磁盘表代替:
服务器不使用临时表来满足某些条件的 UNION
语句。相反,它仅保留临时表创建所需的数据结构,以执行结果列类型转换。该表不完全实例化,也不会写入或从中读取行;行直接发送到客户端。结果是减少了内存和磁盘需求,并且在发送第一行到客户端之前的延迟减少,因为服务器不需要等待最后一个查询块执行完毕。EXPLAIN
和优化器跟踪输出反映了这种执行策略:UNION RESULT
查询块不存在,因为该块对应于从临时表读取的部分。
这些条件使 UNION
语句无需临时表:
-
该union是
UNION ALL
,而不是UNION
或UNION DISTINCT
。 -
没有全局
ORDER BY
子句。 -
该union不是
{INSERT | REPLACE} ... SELECT ...
语句的顶级查询块。
内部临时表可以在内存中保存并由 TempTable
或 MEMORY
存储引擎处理,也可以由 InnoDB
存储引擎在磁盘上保存。
内存中内部临时表的存储引擎
变量 internal_tmp_mem_storage_engine
定义了在内存中内部临时表的存储引擎。允许的值是 TempTable
(默认)和 MEMORY
。
配置会话设置 internal_tmp_mem_storage_engine
需要 SESSION_VARIABLES_ADMIN
或 SYSTEM_VARIABLES_ADMIN
权限。
存储引擎 TempTable
提供了对 VARCHAR
和 VARBINARY
列的高效存储,以及其他二进制大对象类型。
以下变量控制 TempTable
存储引擎的限制和行为:
-
tmp_table_size
:定义了由 TempTable 存储引擎创建的任何单个内存内部临时表的最大大小。当tmp_table_size
限制达到时,MySQL 会自动将内存内部临时表转换为InnoDB
磁盘内部临时表。默认的tmp_table_size
设置是 16777216 字节(16 MiB)。限制
tmp_table_size
是为了防止单个查询消耗过多的全局 TempTable 资源,这可能会影响并发查询的性能,这些查询需要 TempTable 资源。全局 TempTable 资源由temptable_max_ram
和temptable_max_mmap
设置控制。如果
tmp_table_size
限制小于temptable_max_ram
限制,那么内存临时表不能包含超过tmp_table_size
限制的数据。如果tmp_table_size
限制大于temptable_max_ram
和temptable_max_mmap
限制的总和,那么内存临时表不能包含超过temptable_max_ram
和temptable_max_mmap
限制的总和。 -
temptable_max_ram
:定义TempTable存储引擎可以使用的最大RAM量,超过该限制后,TempTable存储引擎将从内存映射文件中分配空间或使用InnoDB磁盘内部临时表,具体取决于您的配置。默认temptable_max_ram
设置为1073741824字节(1GiB)。NoteThe
temptable_max_ram
设置不包括每个线程的线程本地内存块大小,该大小取决于线程的初始内存分配请求。如果请求小于1MB,通常情况下,线程本地内存块大小为1MB。如果请求大于1MB,线程本地内存块大小约等于初始内存请求大小。线程本地内存块在线程退出时释放。 -
temptable_use_mmap
:控制TempTable存储引擎是否从内存映射文件中分配空间或使用InnoDB磁盘内部临时表,当temptable_max_ram
限制被超过时。默认设置为temptable_use_mmap=ON
。NoteThe
temptable_use_mmap
变量已弃用;预计在未来版本的MySQL中删除对其的支持。设置temptable_max_mmap=0
等同于设置temptable_use_mmap=OFF
。 -
temptable_max_mmap
:设置TempTable存储引擎从内存映射文件中分配的最大空间量,超过该限制后,MySQL将使用InnoDB磁盘内部临时表。默认设置为1073741824字节(1GiB)。该限制旨在解决临时目录(tmpdir
)中的内存映射文件使用太多空间的风险。temptable_max_mmap = 0
禁用从内存映射文件的分配,无论temptable_use_mmap
设置如何。
TempTable存储引擎使用内存映射文件的规则如下:
-
临时文件在
tmpdir
变量定义的目录中创建。 -
临时文件在创建和打开后立即删除,因此不再
tmpdir
目录中可见。临时文件占用的空间由操作系统持有,直到临时文件被TempTable存储引擎关闭或mysqld进程关闭时释放。 -
数据从不在RAM和临时文件之间、RAM内部或临时文件之间移动。
-
新的数据存储在 RAM 中,如果在定义的限制内有可用的空间,定义由
temptable_max_ram
。否则,新的数据将存储在临时文件中。 -
如果在 RAM 中有可用的空间可用来存储表数据的一部分,然后将剩余的表数据存储在 RAM 中。
使用 MEMORY
存储引擎的内存临时表(internal_tmp_mem_storage_engine=MEMORY
),MySQL 会自动将内存临时表转换为磁盘表,如果表变得太大。内存临时表的最大大小由 tmp_table_size
或 max_heap_table_size
值定义,取较小的那个值。这与使用 MEMORY
存储引擎显式创建的表不同,对于这些表,只有 max_heap_table_size
变量确定表可以增长的大小,并且没有转换为磁盘格式。
磁盘内部临时表的存储引擎
MySQL 8.3 只使用 InnoDB
存储引擎来存储磁盘内部临时表。(MYISAM
存储引擎不再支持这种用途。)
InnoDB
磁盘内部临时表是在会话临时表空间中创建的,默认情况下位于数据目录中。有关更多信息,请参阅 第 17.6.3.5 节,“临时表空间”。
当内存内部临时表由 TempTable
存储引擎管理时,包含 VARCHAR
列、VARBINARY
列和其他二进制大对象类型列的行将在内存中表示为单元格数组,每个单元格包含一个 NULL
标志、数据长度和数据指针。列值将连续存储在单个内存区域中,不带填充。每个单元格使用 16 字节的存储空间。相同的存储格式也适用于 TempTable
存储引擎从内存映射文件中分配空间时。
当内存内部临时表由 MEMORY
存储引擎管理时,固定长度行格式将被使用。VARCHAR
和 VARBINARY
列值将被填充到最大列长度,以便存储它们作为 CHAR
和 BINARY
列。
磁盘内部临时表总是由 InnoDB
管理的。
使用 MEMORY
存储引擎时,语句可以最初创建一个内存内部临时表,然后如果表变得太大,将其转换为磁盘表。在这种情况下,可能会通过跳过转换并从一开始就在磁盘上创建内部临时表来提高性能。big_tables
变量可以用于强制磁盘存储内部临时表。
当内部临时表在内存或磁盘上创建时,服务器将增加 Created_tmp_tables
值。当内部临时表在磁盘上创建时,服务器将增加 Created_tmp_disk_tables
值。如果在磁盘上创建了太多内部临时表,考虑调整引擎特定的限制,如 内部临时表存储引擎 中所述。
由于已知的限制,Created_tmp_disk_tables
不会统计在内存映射文件中创建的磁盘临时表。默认情况下,TempTable 存储引擎溢出机制会在内存映射文件中创建内部临时表。请参阅 内部临时表存储引擎。
可以使用 memory/temptable/physical_ram
和 memory/temptable/physical_disk
性能架构仪表来监控 TempTable
空间分配来自内存和磁盘。memory/temptable/physical_ram
报告分配的 RAM 数量。memory/temptable/physical_disk
报告从磁盘分配的空间大小,当使用内存映射文件作为 TempTable 溢出机制时。如果 physical_disk
仪表报告的值不是 0,并且使用内存映射文件作为 TempTable 溢出机制,那么在某个时候达到了 TempTable 内存限制。可以在性能架构内存摘要表中查询数据,例如 memory_summary_global_by_event_name
。请参阅 第 29.12.20.10 节,“内存摘要表”。