Temporary Tables MySQLIf you ever had to deal with performance and/or disk space issues related to temporary tables, I bet you eventually found yourself puzzled. There are many possible scenarios depending on the type of temporary table, settings, and MySQL version used. We have observed a pretty long evolution in that matter due to a couple of reasons. One of them was the need to completely eliminate the need to use the deprecated MyISAM engine, and at the same time introduce more performant and reliable alternatives. Another set of improvements was required related to InnoDB, where it was necessary to lower the overhead of temporary tables using that engine.

For that reason, I decided to gather them in a sort of summary which may help to troubleshoot their usage. Due to vast changes between major MySQL releases, I divided the article by them.

MySQL 5.6

(If you are still using that version, you are encouraged to consider upgrading it soon as it has reached EOL.)

User-Created Temporary Tables

When a table is created using CREATE TEMPORARY TABLE clause, it will use the engine defined by default_tmp_storage_engine (defaults to InnoDB) if not explicitly defined otherwise and will be stored inside the directory defined by the tmpdir variable.

An example one may look like this:

But how do you find the file created on disk that stores this table data? While this query may help:

We don’t see the original table name here. Even by looking at the buffer pool, we still don’t have the real name:

Here comes the extension available in the Percona Server for MySQL 5.6 variant – additional information_schema table: GLOBAL_TEMPORARY_TABLES. With that one, we can craft a query that provides a bit more information:

So at least for the InnoDB temp table, we can correlate the exact table name with the file path.

Internal Temporary Tables

These are ones created by MySQL in the process of executing a query. We don’t have any access to such tables, but let’s see how we can investigate their usage.

This type is created in memory (using MEMORY engine) as long as its size doesn’t exceed either tmp_table_size or max_heap_table_size variables, and if no TEXT/BLOB columns are in use. If such a table has to be stored on disk though, in MySQL 5.6 it will use MyISAM storage and also tmpdir used as a location. Quick example, on 10M rows sysbench table, query producing big internal temporary table:

And we can see the related files growing:

It may be difficult to correlate a particular temp table and its client connection though. The only information I found is:

MySQL 5.7

User-Created Temporary Tables

As earlier, the default_tmp_storage_engine variable decides on the engine used. But two changes happened here. InnoDB temporary tables now use a common dedicated shared tablespace – ibtmp1, unless it is compressed. Moreover, we have an additional information_schema view: INNODB_TEMP_TABLE_INFO. Given that, we can get information like below:

But again to correlate with a table name, the Percona Server for MySQL extension needs to be used:

Alternatively, to see also MyISAM and related .frm files, we can use:

Internal Temporary Tables

For internal temporary tables in 5.7, it is similar in terms of in-memory ones. But the default engine for on-disk temp tables is defined via a new variable: internal_tmp_disk_storage_engine, which now defaults also to InnoDB, and also the ibtmp1 tablespace is used to store its contents.

Insight into this shared temporary tablespace is pretty limited. We can check its size and how much free space is currently available. An example view was taken during heavy query ongoing:

And after the query is finished we can see most of the space is freed (FREE_EXTENTS):

However, the tablespace won’t be truncated unless MySQL is restarted:

To see the writing activity (which may turn out to be much higher for a single query than total size growth made by it):

MySQL 8.0

For simplicity, let’s skip how things worked before 8.0.16 and discuss only how it works since then, as the changes in that matter are quite significant:

  • internal_tmp_disk_storage_engine variable was removed and it is no longer possible to use the MyISAM engine for internal temporary tables
  • shared ibtmp1 table space is no longer used for either temporary table type
  • a pool of new Session Temporary Tablespaces was introduced to handle both user and internal temporary tables on disk and is located by default in the main data directory
  • the new TempTable engine for in-memory tables uses both the space in memory as well as mmapped files on disk

User-Created Temporary Tables

For an example temporary table:

We can correlate which file was used from that pool by looking at the space number:

But again, no way to look for the table name. Fortunately, Percona Server for MySQL still has the GLOBAL_TEMPORARY_TABLES table, so given the three available system views, we can get better information on user-created temporary tables using various engines, like below:

Similar to ibtmp1, these tablespaces are not truncated apart from MySQL restart.

From the above, we can see that user connection 10 has one open InnoDB temporary table, and connection 13 has three temporary tables using three different engines.

Internal Temporary Tables

While a heavy query is running in connection 10, we can get the following views:

From the above, we can see the query created a huge temporary table, that first exceeded temptable_max_ram variable and continued to grow in a mmapped file (still TempTable engine), but as also temptable_max_mmap was reached, the table had to be converted to on-disk InnoDB intrinsic table. The same pool of temporary InnoDB tables is used in this case, but we can see the purpose information, depending if the table is external (user-created) or internal.

The mmapped file is not visible in the file system as it has deleted state, but can be watched with lsof:

It is important to know here, that as long as mmapped space has not exceeded, the Created_tmp_disk_tables counter is not incremented even though a file is created on disk here.

Also, in Percona Server for MySQL, the extended slow log, the size of temporary tables when the TempTable engine is used, is not accounted for: https://jira.percona.com/browse/PS-5168 – it shows “Tmp_table_sizes: 0”.

In some use cases, there are problems reported with the TempTable. It is possible to switch back to the old Memory engine via the internal_tmp_mem_storage_engine variable if needed.

References

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Marko Mäkelä

Some things could still be improved about temporary tables in MySQL. As far as I understand, in a workload that involves writes to both temporary and persistent InnoDB tables, current (or former!) pages of temporary tables may be unnecessarily written to the data files. Starting with MariaDB Server 10.5.9, unnecessary writes of freed pages (such as after DROP TEMPORARY TABLE) will be avoided. Starting with MariaDB 10.5.12, pages of temporary tables would only be written out if we run out of buffer pool (LRU eviction flushing), never as part of checkpoint flushing.

Ross

Good to see ever-relevant topics like this.

On a tangent from this post, can we check metrics for resource usage?

More than the “SHOW” status changes in created_tmp_tables, but also how much temp table usage hits mutex resources and other scale-related issues?

Reason for asking: We know (thanks to earlier Percona blog!) that INSERTs on PK-less/unique key-less tables force the use of the gen_clust_index, and in turn, use a global resource. Global resource as well for DROP/CREATE on temporary tables. Can this “hit” be measured across these MySQL versions? Percona flavor? MariaDB?

Rahul

Following statement is partially correct.

  • shared ibtmp1 table space is no longer used for either temporary table type

As per the manual

> The global temporary tablespace (ibtmp1) stores rollback segments for changes made to user-created temporary tables.