# 2.13.1 临时表优化

## 1. 背景

MySQL包括两类临时表，一类是通过create temporary table创建的临时表，一类是在query过程中using temporary而创建的临时表。\
5.7之前，using temporary创建的临时表，默认只能使用myisam引擎，而在5.7之后，可以选择InnoDB引擎来创建。

临时表的引擎选择使用下面的这两个参数来决定：

```
mysql>show global variables like '%tmp%';
+----------------------------------+---------------------------------------+
| Variable_name                    | Value                                 |
+----------------------------------+---------------------------------------+
| default_tmp_storage_engine       | InnoDB                                |
| internal_tmp_disk_storage_engine | InnoDB                                |
```

## 2. 临时表空间

5.7之后，使用了独立的临时表空间来存储临时表数据，但不能是压缩表。临时表空间在实例启动的时候进行创建，shutdown的时候进行删除。

例如如下的配置：

```
mysql> show global variables like '%innodb_temp%'; 
+----------------------------+-----------------------+

| Variable_name              | Value                 |

+----------------------------+-----------------------+

| innodb_temp_data_file_path | ibtmp1:12M:autoextend |

+----------------------------+-----------------------+
```

create temporary table和using temporary table将共用这个临时表空间。

## 3. 临时表优化

临时表会伴随着大量的数据写入和读取，尤其是internal\_tmp\_table。所以，InnoDB专门对临时表进行了优化。\
InnoDB使用如下两个标示临时表：

```
dict_tf2_temporary： 表示普通临时表  
dict_tf2_intrinsic： 表示内部临时表
```

这两个标示，会在IBD文件的segment header占用两个bit位。intrinsic一定是temproary，也就是temproary上进行的优化\
完全适用于intrinsic表上。

**下面来看下具体的优化：**

## 3.1. redo

临时表在连接断开或者数据库实例关闭的时候，会进行删除，所以，临时表的数据不需要redo来保护，即recovery的过程中\
不恢复临时表，只有临时表的metadata使用了redo保护，保护元数据的完整性，以便异常启动后进行清理工作。

临时表的元数据，5.7之后，使用了一个独立的表进行保存，这样就不要使用redo保护，元数据也只保存在内存中。\
但这有一个前提，必须使用共享的临时表空间，如果使用file-per-table，仍然需要持久化元数据，以便异常恢复清理。

## 3.2 undo

temporary table仍然需要语句级的回滚，所以，需要为数据生成undo。但intrinsic table不需要回滚，所以，intrinsic table\
减少了undo的生成，性能更高。

## 3.3 lock

因为临时表只有本线程可以看见，所以减少了InnoDB的加锁过程。

可以看下insert的时候，进行的分支判断：

```c
row_insert_for_mysql(
    const byte*        mysql_rec,
    row_prebuilt_t*        prebuilt)
{
    /* For intrinsic tables there a lot of restrictions that can be
    relaxed including locking of table, transaction handling, etc.
    Use direct cursor interface for inserting to intrinsic tables. */
    if (dict_table_is_intrinsic(prebuilt->table)) {
        return(row_insert_for_mysql_using_cursor(mysql_rec, prebuilt));
    } else {
        return(row_insert_for_mysql_using_ins_graph(
            mysql_rec, prebuilt));
    }
}
```

row\_insert\_for\_mysql\_using\_cursor直接跳过了加锁的lock\_table过程。

然后，如果是intrinsic table，就直接插入，减少了undo的生成。\
如果不是，需要加lock，并生成undo信息。

```
if (dict_table_is_intrinsic(index->table)) {

            index->rec_cache.rec_size = rec_size;

            *rec = page_cur_tuple_direct_insert(
                page_cursor, entry, index, n_ext, mtr);
        } else {
            /* Check locks and write to the undo log,
            if specified */
            err = btr_cur_ins_lock_and_undo(flags, cursor, entry,
                            thr, mtr, &inherit);
```

插入的时候，如果是临时表。就关闭redo的生成。如下面的代码所示：

```
if (dict_table_is_temporary(index->table)) {
        /* Disable REDO logging as the lifetime of temp-tables is
        limited to server or connection lifetime and so REDO
        information is not needed on restart for recovery.
        Disable locking as temp-tables are local to a connection. */

        ut_ad(flags & BTR_NO_LOCKING_FLAG);
        ut_ad(!dict_table_is_intrinsic(index->table)
              || (flags & BTR_NO_UNDO_LOG_FLAG));

        mtr.set_log_mode(MTR_LOG_NO_REDO);
    }
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hhyo.gitbook.io/mysql5-7/2/24innodb-gong-neng-you-hua/241-lin-shi-biao-you-hua.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
