PingKai Logo下载

临时表

临时表可以被看作是一种重用查询结果的技术。

如果你想了解 Bookshop 应用中最年长作者的相关信息,可能会编写多个使用最年长作者列表的查询。

例如,你可以使用以下语句从 authors 表中获取前 50 位最年长的作者:

SELECT a.id, a.name, (IFNULL(a.death_year, YEAR(NOW())) - a.birth_year) AS age
FROM authors a
ORDER BY age DESC
LIMIT 50;

结果如下:

+------------+---------------------+------+
| id         | name                | age  |
+------------+---------------------+------+
| 4053452056 | Dessie Thompson     |   80 |
| 2773958689 | Pedro Hansen        |   80 |
| 4005636688 | Wyatt Keeling       |   80 |
| 3621155838 | Colby Parker        |   80 |
| 2738876051 | Friedrich Hagenes   |   80 |
| 2299112019 | Ray Macejkovic      |   80 |
| 3953661843 | Brandi Williamson   |   80 |
...
| 4100546410 | Maida Walsh         |   80 |
+------------+---------------------+------+
50 行结果(0.01 秒)

为了后续查询的便利,你需要缓存此查询的结果。在使用普通表存储时,应注意避免不同会话之间的表名重复问题,以及及时清理中间结果,因为这些表在批量查询后可能不再使用。

创建临时表

为了缓存中间结果,TiDB 在 v5.3.0 版本中引入了临时表功能。TiDB 会在会话结束后自动删除本地临时表,免除你管理因中间结果增加带来的麻烦。

临时表的类型

TiDB 中的临时表分为两种:本地临时表和全局临时表。

  • 本地临时表:表定义和数据仅对当前会话可见。此类型适合在会话中临时存储中间数据。
  • 全局临时表:表定义对整个 TiDB 集群可见,表中的数据仅对当前事务可见。此类型适合在事务中临时存储中间数据。

创建本地临时表

在创建本地临时表之前,你需要为当前数据库用户添加 CREATE TEMPORARY TABLES 权限。

你可以使用 CREATE TEMPORARY TABLE <table_name> 语句创建临时表。默认类型为本地临时表,仅对当前会话可见。

CREATE TEMPORARY TABLE top_50_eldest_authors (
    id BIGINT,
    name VARCHAR(255),
    age INT,
    PRIMARY KEY(id)
);

创建临时表后,可以使用 INSERT INTO table_name SELECT ... 语句将上述查询的结果插入到刚创建的临时表中。

INSERT INTO top_50_eldest_authors
SELECT a.id, a.name, (IFNULL(a.death_year, YEAR(NOW())) - a.birth_year) AS age
FROM authors a
ORDER BY age DESC
LIMIT 50;

结果如下:

Query OK, 50 rows affected (0.03 sec)
Records: 50  Duplicates: 0  Warnings: 0

创建全局临时表

要创建全局临时表,可以添加 GLOBAL 关键字,并以 ON COMMIT DELETE ROWS 结尾,表示在当前事务结束后删除该表。

CREATE GLOBAL TEMPORARY TABLE IF NOT EXISTS top_50_eldest_authors_global (
    id BIGINT,
    name VARCHAR(255),
    age INT,
    PRIMARY KEY(id)
) ON COMMIT DELETE ROWS;

在向全局临时表插入数据时,必须显式声明事务的开始,使用 BEGIN。否则,数据在执行完 INSERT INTO 语句后会被清除。因为在自动提交模式下,INSERT INTO 语句执行完后事务会自动提交,事务结束时全局临时表会被清空。

查看临时表

使用 SHOW [FULL] TABLES 语句可以查看现有的全局临时表列表,但不能看到任何本地临时表。目前,TiDB 还没有类似 information_schema.INNODB_TEMP_TABLE_INFO 的系统表用以存储临时表信息。

例如,你可以在表列表中看到全局临时表 top_50_eldest_authors_global,但看不到 top_50_eldest_authors 表。

+-------------------------------+------------+
| Tables_in_bookshop            | Table_type |
+-------------------------------+------------+
| authors                       | BASE TABLE |
| book_authors                  | BASE TABLE |
| books                         | BASE TABLE |
| orders                        | BASE TABLE |
| ratings                       | BASE TABLE |
| top_50_eldest_authors_global  | BASE TABLE |
| users                         | BASE TABLE |
+-------------------------------+------------+
9 行结果(0.00 秒)

查询临时表

一旦临时表准备就绪,你可以像查询普通数据表一样查询它:

SELECT * FROM top_50_eldest_authors;

你也可以通过 Multi-table join queries 引用临时表中的数据到你的查询中:

EXPLAIN SELECT ANY_VALUE(ta.id) AS author_id, ANY_VALUE(ta.age), ANY_VALUE(ta.name), COUNT(*) AS books
FROM top_50_eldest_authors ta
LEFT JOIN book_authors ba ON ta.id = ba.author_id
GROUP BY ta.id;

不同于 view,查询临时表会直接从临时表中获取数据,而不是执行插入时使用的原始查询。在某些情况下,这可以提升查询性能。

删除临时表

会话中的本地临时表在 会话 结束后会自动删除,包括数据和表结构。事务中的全局临时表在 事务 结束时会自动清空,但表结构仍然存在,需要手动删除。

要手动删除本地临时表,可以使用 DROP TABLE 或 DROP TEMPORARY TABLE 语法。例如:

DROP TEMPORARY TABLE top_50_eldest_authors;

要手动删除全局临时表,可以使用 DROP TABLE 或 DROP GLOBAL TEMPORARY TABLE 语法。例如:

DROP GLOBAL TEMPORARY TABLE top_50_eldest_authors_global;

限制

关于 TiDB 中临时表的限制,请参见 Compatibility restrictions with other TiDB features。

阅读更多

需要帮助?

在 Discord 或 Slack 上向社区提问,或 提交支持工单。