LightDBにおけるグローバル一時テーブルの実装メカニズム

概要

グローバル一時テーブル(Global Temporary Table)はデータベースにおける特殊なテーブルタイプであり、特定のセッションに依存せずに作成され、複数のセッションで共有・アクセスできます。グローバル一時テーブルのデータは現在のデータベースセッションのライフサイクル内でのみ表示され、セッション終了時に自動的に破棄されます。

グローバル一時テーブルは通常、中間結果セットや一時データの一時的な保存に使用され、セッション内またはセッション間での共有と処理に役立ちます。これにより、複数のクエリや操作間でデータを共有する必要があるシナリオに特に有用であり、一時テーブル作成時の名前競合問題を回避できます。

重要な点として、グローバル一時テーブルの定義は永続的ですが、テーブル内のデータは作成したセッション内でのみ表示されることに注意してください。他のセッションは同じテーブル名でグローバル一時テーブルにアクセスできますが、他のセッションが挿入したデータは表示されません。グローバル一時テーブルのデータはセッション終了時に自動的にクリアされ、データベースの永続ストレージに影響を与えません。

グローバル一時テーブルの作成

LightDBでは、グローバル一時テーブルはトランザクションレベルとセッションレベルの2種類に分かれ、デフォルトはトランザクションレベルのグローバル一時テーブルです。トランザクションレベルのグローバル一時テーブルのデータは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を生成 この内容はPostgreSQL公式ドキュメントを参照してください
  • create table構文を変更し、実行フェーズでPlannedStmtの一部の属性を変更
  • 特殊なスキーマ命名法を利用して、トランザクションレベルまたはセッションレベルのCRUD操作を実現

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フィールドにRELPERSISTENCE_GLOBAL_TEMP値を割り当てます。

処理ロジックの変更

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の削除

関数呼び出しロジックは以下の通りです:

  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)の実行には2つの段階が関係します:

  1. 構文解析段階での処理
  2. テーブルへの通常のデータ挿入操作の実行

グローバル一時テーブルに対するinsert/select/delete/update操作の際には、構文解析段階でltgtt_process_rte関数が呼び出されます。この関数は特殊な命名スキーマ内にunloggedテーブルを作成するためにltgtt_create_temp_table関数を呼び出します。

関数呼び出しスタックは以下の通りです:

通常のテーブルへのデータ挿入時の呼び出しスタックは以下の通りです:

データのクエリ

データクエリのフローはデータ挿入のフローと基本的に同じです。データ挿入はPlanTree実行時にPortalRunMultiを呼び出し、データクエリはPortalRunSelectを呼び出します。

タグ: lightdb グローバル一時テーブル データベース実装 PostgreSQL

5月18日 23:57 投稿