简介
全局临时表(Global Temporary Table)是数据库中一种特殊类型的表,它在创建时与特定的会话无关,并且可以被多个会话共享和访问。全局临时表的数据只在当前数据库会话的生命周期内可见,并且在会话结束后自动销毁。
全局临时表通常用于临时存储中间结果集或临时数据,以便在会话内部或会话之间进行共享和处理。它们对于需要在多个查询或操作之间共享数据的场景非常有用,同时避免了创建临时表时的名称冲突问题。
需要注意的是,全局临时表的定义是永久性的,但表中的数据只在创建它的会话中可见。其他会话可以通过相同的表名访问全局临时表,但它们将看不到其他会话插入的数据。全局临时表的数据在会话结束后会自动清空,不会对数据库的永久存储产生影响。
创建全局临时表
在 lightdb 中,全局临时表分为事务级和会话级两种,默认是事务级全局临时表。事务级全局临时表的数据在执行 commit
操作后就被删除,而会话级全局临时表数据则在退出当前会话或连接后被删除。
-- 默认是事务级别
create global temp table g_bar(i int);
-- 可以创建会话级别
create global temp table g_bar2(i int) on commit preserve rows;
详情看这个终端操作实录
实现机制
概览
lightdb 中全局临时表的实现机制有:
- 生成系统表
lt_global_temp_table_ext
该内容将会在后续文章中介绍,不是此文的重点 - 修改 create table 语法并在执行器阶段修改 PlannedStmt 一些属性
- 利用特殊的 schema 命名法实现会话级别或事务级别的增删改查
创建 GTT
以下面这条 sql 语句为例:
create global temp table g_foo(i int);
为了实现这条 sql 语句,需要:
- 修改
CreateStmt
语法的解析规则 - 修改执行器对该条规则的处理
- 向系统表 lt_global_temp_table_ext 中添加一条记录
修改语法
CreateStmt 语法规则:
CreateStmt: CREATE OptTemp TABLE qualified_name ... {
CreateStmt *n = makeNode(CreateStmt);
$4->relpersistence = $2;
}
OptTemp: TEMP { $$ = RELPERSISTENCE_TEMP; }
| GLOBAL TEMP { $$ = RELPERSISTENCE_GLOBAL_TEMP; }
| UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; }
在 OptTemp
节点中增加 GLOBAL TEMP
语法,当语法解析器遇到 GLOBAL TEMP
的时候,将 RELPERSISTENCE_GLOBAL_TEMP
值赋值给 relpersistence
字段。
修改处理逻辑
在 ProcessUtilitySlow 函数中处理 PlannedStmt:
Node* parsetree = pstmt->utilityStmt;
if ((nodeTag(parsetree) == T_CreateStmt) &&
(LT_GttCheckCreateGttStmt(ptstmt) == true))
{
// 将 RELPERSISTENCE_GLOBAL_TEMP 值替换为 RELPERSISTENCE_UNLOGGED
ptstmt->relation->relpersistence = RELPERSISTENCE_UNLOGGED;
if (ptstmt->oncommit == ONCOMMIT_PRESERVE_ROWS)
ispreserved = true;
ptstmt->oncommit = ONCOMMIT_NOOP;
isgtt = true;
}
// 这个函数处理建表的核心逻辑,待后续文章分析
DefineRelation(...);
if (isgtt)
{
// 向系统表 lt_global_temp_table_ext 中插入一条记录
LT_GttInsertGttInfo(ptstmt, ispreserved);
}
函数调用栈
删除 GTT
函数调用逻辑如下:
- 打开系统表 lt_global_temp_table_ext
- 查找系统缓存中是否有关于要删除表的数据
- 如果找到了,就从系统缓存中删除。在删除前,调用 simple_heap_delete 处理删表核心逻辑。
- 关闭系统表 lt_global_temp_table_ext
simple_heap_delete 的核心逻辑待后续文章分析。
插入数据
在执行 insert into g_foo values (1)
时会涉及两个阶段:
- 语法解析阶段时的处理
- 执行正常的向表中插入数据的操作
在对全局临时表进行 insert/select/delete/update 操作时,都会在语法解析阶段调用 ltgtt_process_rte
函数。该函数调用 ltgtt_create_temp_table 函数在特殊命名的 schema 中创建 unlogged table. ltgtt_create_temp_table
函数在后续文章中再详细解释。
函数调用栈如下:
正常的向表中插入数据时候的调用栈如下:
查询数据
查询数据流程和插入数据流程基本一致,插入数据在执行 PlanTree 时调用的是 PortalRunMulti, 而查询数据调用的是 PortalRunSelect.