10.4.4 MySQL 中内部临时表的使用
在某些情况下,服务器在处理语句时创建内部临时表。用户无法直接控制何时发生这种情况。
服务器在以下情况下创建临时表:
-
评估
UNION
语句,除非后续描述的例外情况。 -
评估使用
TEMPTABLE
算法、UNION
或聚合的视图。 -
评估派生表(见第15.2.15.8节,“派生表”)。
-
评估通用表达式(见第15.2.20节,“WITH (通用表达式)”)。
-
为子查询或半连接物化创建的表(见第10.2.2节,“优化子查询、派生表、视图引用和通用表达式”)。
-
评估包含
ORDER BY
子句和不同GROUP BY
子句的语句,或者在join队列中的第一个表以外的表中包含ORDER BY
或GROUP BY
子句的语句。 -
评估
DISTINCT
与ORDER BY
组合可能需要临时表。 -
对于使用
SQL_SMALL_RESULT
修饰符的查询,MySQL将使用内存临时表,除非查询还包含需要磁盘存储的元素(后续描述)。 -
为了评估
INSERT ... SELECT
语句,该语句从同一表中选择和插入数据,MySQL创建一个内部临时表来存储来自SELECT
的行,然后将这些行插入目标表。请参阅第15.2.7.1节,“INSERT ... SELECT Statement”。 -
多表
UPDATE
语句的评估。 -
对
GROUP_CONCAT()
或COUNT(DISTINCT)
表达式的评估。 -
窗口函数(请参阅第14.20节,“Window Functions”)使用临时表,如有必要。
要确定语句是否需要临时表,请使用EXPLAIN
,并检查Extra
列,看看是否说Using temporary
(见第10.8.1节,“使用 EXPLAIN 优化查询”)。EXPLAIN
不一定会说Using temporary
对于派生或物化的临时表。对于使用窗口函数的语句,EXPLAIN
与FORMAT=JSON
总是提供关于窗口步骤的信息。如果窗口函数使用临时表,它将在每个步骤中指示。
一些查询条件会阻止使用内存临时表,在这种情况下,服务器将使用磁盘表แทน:
服务器不使用UNION
语句来满足某些条件,而是保留了临时表创建所需的数据结构,以便执行结果列类型转换。该表未完全实例化,未写入或读取任何行;行直接发送给客户端。结果是减少了内存和磁盘需求,以及在客户端接收第一个行之前的延迟,因为服务器不需要等待最后一个查询块执行。EXPLAIN
和优化器跟踪输出反映了这个执行策略:UNION RESULT
查询块不存在,因为该块对应于从临时表读取的部分。
以下条件使UNION
语句在不使用临时表的情况下进行评估:
-
并集是
UNION ALL
,而不是UNION
或UNION DISTINCT
。 -
没有全局的
ORDER BY
子句。 -
并集不是一个
{INSERT | REPLACE} ... SELECT ...
语句的顶级查询块。
内部临时表可以在内存中被TempTable
或MEMORY
存储引擎处理,也可以由InnoDB
存储引擎存储到磁盘上。
Storage Engine for In-Memory Internal Temporary 表
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大小,直到它开始从内存映射文件中分配空间或MySQL开始使用InnoDB磁盘内部临时表,取决于您的配置。默认temptable_max_ram
设置值是服务器上的总内存的3%,最小和最大默认范围为1-4 GB。在MySQL 8.4之前,缺省值为1GiB。Notetemptable_max_ram
设置不考虑使用TempTable存储引擎的每个线程分配的线程本地内存块。线程本地内存块大小取决于线程的首次内存分配请求的大小。如果请求小于1MB,通常情况下是这样,那么线程本地内存块大小为1MB。如果请求大于1MB,那么线程本地内存块约与初始内存请求相同。线程本地内存块直到线程退出被保留在线程本地存储中。 -
temptable_用mmap
: 控制TempTable
存储引擎是否从内存映射文件中分配空间,或者MySQL使用InnoDB
磁盘内部临时表,当temptable_max_ram
限制被超过时。默认设置为temptable_用mmap=OFF
。Notetemptable_用mmap
变量已弃用;在MySQL的未来版本中,预计将其支持移除。设置temptable_max_mmap=0
等同于设置temptable_用mmap=OFF
。 -
temptable_max_mmap
: 设置 TempTable 存储引擎允许从内存映射文件中分配的最大内存量,直到 MySQL 开始使用 InnoDB 硬盘内部临时表。默认设置为 0(禁用)。该限制旨在解决临时目录 (tmpdir
) 中内存映射文件使用太多空间的风险。temptable_max_mmap = 0
禁用从内存映射文件中分配,实际上禁用了它们的使用,无论是temptable_use_mmap
设置为何。
TempTable 存储引擎对内存映射文件的使用受以下规则管制:
-
临时文件在由
tmpdir
变量定义的目录中创建。 -
临时文件在被创建和打开后立即删除,因此不留存在
tmpdir
目录中。临时文件占用的空间由操作系统持有,直到临时文件被 TempTable 存储引擎关闭或 mysqld 进程关闭。 -
数据从不在 RAM 和临时文件之间、在 RAM 之间或在临时文件之间移动。
-
如果内存中有可用空间,且该空间不超过由
temptable_max_ram
定义的限制,则新的数据将被存储在RAM中。否则,新的数据将被存储在临时文件中。 -
如果某个表的一部分数据已经写入到临时文件中,然后内存中又有可用空间,那么该表剩余的数据可能会被存储在RAM中。
使用internal_tmp_mem_storage_engine=MEMORY
将内存临时表转换为磁盘表,如果该表变得太大。内存临时表的最大大小由tmp_ table_size
或max_heap_table_size
值,取决于哪个值小。这个行为与使用CREATE TABLE
创建的MEMORY表不同。在这种情况下,只有max_heap_table_size
变量确定了表可以增长到多大,且不会将表转换为磁盘格式。
Storage Engine for On-Disk Internal Temporary 表
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
值。如果太多的内部临时表被创建到磁盘上,请考虑调整引擎特定的限制,详见 Internal Temporary Table Storage Engine。
由于已知的限制,Created_tmp_disk_tables
不会统计内存映射文件中创建的临时表。默认情况下,TempTable 存储引擎溢出机制将内部临时表创建在内存映射文件中。请参阅Internal Temporary Table Storage Engine。
性能_schema 中的memory/temptable/physical_ram
和memory/temptable/physical_disk
工具可以用来监控TempTable
空间分配情况。memory/temptable/physical_ram
报告已分配的RAM大小。memory/temptable/physical_disk
报告从磁盘中分配的空间大小,当使用内存映射文件作为 TempTable 溢出机制时。如果physical_disk
工具报告的值不是0,并且使用内存映射文件作为 TempTable 溢出机制,那么某个时间点TempTable 内存限制被达到。可以在性能_schema 中的内存总结表中查询数据,例如memory_summary_global_by_event_name
。请参阅第29.12.20.10节,“内存总结表”。