在某些情况下,服务器会在处理语句时创建内部临时表。用户无法直接控制何时发生这种情况。
服务器会在以下情况下创建临时表:
评估
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
。对于使用窗口函数的语句,使用 FORMAT=JSON
的 EXPLAIN
始终提供有关窗口步骤的信息。如果窗口函数使用临时表,则会在每个步骤中指示。
某些查询条件会阻止使用内存中临时表,在这种情况下,服务器会改用磁盘表:
对于满足某些条件的 UNION
语句,服务器不使用临时表。相反,它仅保留临时表创建中执行结果列类型转换所需的数据结构。该表未完全实例化,并且没有行写入或从中读取;行直接发送到客户端。结果是减少了内存和磁盘需求,并且缩短了将第一行发送到客户端之前的延迟,因为服务器不需要等到最后一个查询块执行完毕。 EXPLAIN
和优化器跟踪输出反映了此执行策略:UNION RESULT
查询块不存在,因为该块对应于从临时表读取的部分。
以下条件使 UNION
有资格在没有临时表的情况下进行评估
该联合是
UNION ALL
,而不是UNION
或UNION DISTINCT
。没有全局
ORDER BY
子句。该联合不是
{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
存储引擎开始从内存映射文件分配空间或 MySQL 开始使用InnoDB
磁盘上内部临时表之前(取决于您的配置)可以使用的最大 RAM 量。默认的temptable_max_ram
设置值为服务器可用总内存的 3%,最小和最大默认范围为 1-4 GB。在 MySQL 8.4 之前,默认值为 1GiB。注意temptable_max_ram
设置不考虑分配给使用TempTable
存储引擎的每个线程的线程本地内存块。线程本地内存块的大小取决于线程的第一个内存分配请求的大小。如果请求小于 1MB(在大多数情况下是这样),则线程本地内存块大小为 1MB。如果请求大于 1MB,则线程本地内存块的大小与初始内存请求的大小大致相同。线程本地内存块保存在线程本地存储中,直到线程退出。temptable_use_mmap
:控制当超过temptable_max_ram
限制时,TempTable
存储引擎是否从内存映射文件分配空间或 MySQL 是否使用InnoDB
磁盘上内部临时表。默认设置为temptable_use_mmap=OFF
。注意temptable_use_mmap
变量已弃用;预计在未来版本的 MySQL 中将删除对它的支持。设置temptable_max_mmap=0
等效于设置temptable_use_mmap=OFF
。temptable_max_mmap
:设置在 MySQL 开始使用InnoDB
磁盘上内部临时表之前,允许 TempTable 存储引擎从内存映射文件分配的最大内存量。默认设置为 0(禁用)。此限制旨在解决内存映射文件在临时目录(tmpdir
)中使用过多空间的风险。temptable_max_mmap = 0
禁用从内存映射文件分配,从而有效地禁用它们的使用,而不管temptable_use_mmap
设置如何。
TempTable
存储引擎对内存映射文件的使用受以下规则约束
临时文件是在
tmpdir
变量定义的目录中创建的。临时文件在创建和打开后立即删除,因此在
tmpdir
目录中不可见。临时文件占用的空间由操作系统在临时文件打开时持有。当TempTable
存储引擎关闭临时文件或mysqld
进程关闭时,将回收该空间。数据永远不会在 RAM 和临时文件之间、RAM 内或临时文件之间移动。
如果在
temptable_max_ram
定义的限制内有可用空间,则新数据将存储在 RAM 中。否则,新数据将存储在临时文件中。如果在将表的某些数据写入临时文件后 RAM 中有可用空间,则剩余的表数据可能会存储在 RAM 中。
当对内存中临时表使用 MEMORY
存储引擎时(internal_tmp_mem_storage_engine=MEMORY
),如果内存中临时表变得太大,MySQL 会自动将其转换为磁盘上的表。内存中临时表的最大大小由 tmp_table_size
或 max_heap_table_size
值(以较小者为准)定义。这与使用 CREATE TABLE
显式创建的 MEMORY
表不同。对于此类表,只有 max_heap_table_size
变量决定表可以增长多大,并且不会转换为磁盘格式。
磁盘上内部临时表的存储引擎
MySQL 8.4 仅使用 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 量。当使用内存映射文件作为 TempTable 溢出机制时,memory/temptable/physical_disk
会报告从磁盘分配的空间量。如果 physical_disk
工具报告的值不是 0 并且使用内存映射文件作为 TempTable 溢出机制,则表示在某个时间点达到了 TempTable 内存限制。可以在性能模式内存摘要表(如 memory_summary_global_by_event_name
)中查询数据。请参阅 第 29.12.20.10 节“内存摘要表”。