lightdb 全局临时表实现机制探究

发布时间 2023-06-25 08:25:21作者: winter-loo

简介

全局临时表(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 语句,需要:

  1. 修改 CreateStmt 语法的解析规则
  2. 修改执行器对该条规则的处理
  3. 向系统表 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);
}

函数调用栈

create_gtt

删除 GTT

函数调用逻辑如下:

  1. 打开系统表 lt_global_temp_table_ext
  2. 查找系统缓存中是否有关于要删除表的数据
  3. 如果找到了,就从系统缓存中删除。在删除前,调用 simple_heap_delete 处理删表核心逻辑。
  4. 关闭系统表 lt_global_temp_table_ext

simple_heap_delete 的核心逻辑待后续文章分析。

插入数据

在执行 insert into g_foo values (1) 时会涉及两个阶段:

  1. 语法解析阶段时的处理
  2. 执行正常的向表中插入数据的操作

在对全局临时表进行 insert/select/delete/update 操作时,都会在语法解析阶段调用 ltgtt_process_rte 函数。该函数调用 ltgtt_create_temp_table 函数在特殊命名的 schema 中创建 unlogged table. ltgtt_create_temp_table 函数在后续文章中再详细解释。

函数调用栈如下:
insert_into_gtt

正常的向表中插入数据时候的调用栈如下:

查询数据

查询数据流程和插入数据流程基本一致,插入数据在执行 PlanTree 时调用的是 PortalRunMulti, 而查询数据调用的是 PortalRunSelect.