# データベース設計書

## 概要

本ドキュメントは、TensorFlowプロジェクトにおけるデータベース設計を記載する。TensorFlowは機械学習のトレーニングおよび推論を行うフレームワークであり、TensorBoard向けのサマリーデータ永続化のためにSQLite データベースを使用している。

データベーススキーマは `tensorflow/core/summary/schema.cc` の `SetupTensorboardSqliteDb()` 関数で定義されており、TensorBoardのデータ（ユーザー、実験、ラン、タグ、テンソル、グラフ情報）を管理する。SQLite のアプリケーションIDとして `0xfeedabee` が設定される。

また、`tensorflow/core/kernels/data/experimental/sql/` 配下に、SQLデータセットとして外部データベースへのクエリ接続を行う仕組み（`QueryConnection` インタフェースおよび `SqliteQueryConnection` 実装）が存在するが、これらはスキーマ定義を持たず、外部データソースへの読み取り専用接続であるため、本設計書の対象外とする。

## テーブル一覧

| テーブル名 | 対応エンティティ | 説明 |
| --- | --- | --- |
| Ids | ID管理 | システム全体で一意な永続IDを管理するテーブル |
| Descriptions | 説明文 | 任意のリソースに紐づくMarkdown形式の説明文を管理するテーブル |
| Tensors | テンソル | 0..n次元の数値または文字列テンソルデータを格納するテーブル |
| TensorStrings | テンソル文字列 | 1..n次元のDT_STRINGテンソルのフラット化された内容を格納するテーブル |
| Tags | タグ | テンソル系列を表すタグ情報を管理するテーブル |
| Runs | ラン | TensorFlowモデルのトレーニング/テストの1回分の実行を管理するテーブル |
| Experiments | 実験 | ランをグループ化する実験を管理するテーブル |
| Users | ユーザー | TensorBoardのユーザーを管理するテーブル |
| Graphs | グラフ | ランにおけるテンソルフローのグラフ定義を管理するテーブル |
| Nodes | ノード | グラフ内の頂点（ノード）を管理するテーブル |
| NodeInputs | ノード入力 | グラフ内のノード間の有向エッジ（入力接続）を管理するテーブル |

## 各テーブル定義

### 1. Ids

システム全体で一意な永続IDを管理するテーブル。URLで使用可能で、テーブル間で一意性が保証されるIDを乱数生成器と組み合わせて効率的に生成するために使用される。IDは `[1, 2^47)` の範囲でなければならない。0はNULLと同じ意味を持つ。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | INTEGER | NO (PRIMARY KEY) | システム全体で一意な永続ID。rowidと同一。範囲は [1, 2^47) |

**インデックス**: なし（PRIMARY KEYによる暗黙的なインデックス）

### 2. Descriptions

任意のリソース（永続IDを持つもの）に紐づくMarkdown形式の説明文を管理するテーブル。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | INTEGER | NO (PRIMARY KEY) | 関連するリソースのfoo_id（Idsテーブルの値に対応） |
| description | TEXT | YES | 任意のNUL終端Markdownテキスト |

**インデックス**: なし（PRIMARY KEYによる暗黙的なインデックス）

### 3. Tensors

0..n次元の数値または文字列テンソルデータを格納するテーブル。各テンソルはseries（系列）とstep（ステップ）で識別される。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| series | INTEGER | YES | 関連リソースの永続ID（例: tag_id）。NULLの場合、未定義の目的で使用可能 |
| step | INTEGER | YES | 系列内でテンソルを一意に順序付けるための任意の数値 |
| dtype | INTEGER | YES | tensorflow::DataType ID（例: DT_INT64=9）。NULLまたは0の場合はプレースホルダ行 |
| computed_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。テンソルが計算された時刻 |
| shape | TEXT | YES | テンソルの各次元の長さを表すカンマ区切りのint64値リスト。空文字列はスカラー |
| data | BLOB | YES | リトルエンディアンの生テンソルメモリ |

**インデックス**:
- `TensorSeriesStepIndex`: UNIQUE ON (series, step) WHERE series IS NOT NULL AND step IS NOT NULL

### 4. TensorStrings

1..n次元のDT_STRINGテンソルのフラット化された内容を格納するテーブル。関連するテンソルに対する行数は、Tensors.shapeの積と等しくなければならない。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| tensor_rowid | INTEGER | NO | Tensors.rowidへの参照 |
| idx | INTEGER | NO | フラット化されたテンソル内のインデックス（0始まり） |
| data | BLOB | YES | 特定のインデックスにおける文字列値。NUL文字を含むことが可能 |

**インデックス**:
- `TensorStringIndex`: UNIQUE ON (tensor_rowid, idx)

### 5. Tags

テンソルの系列を表すタグ情報を管理するテーブル。各タグはランに属し、プラグインによるディスパッチのためのメタデータを保持する。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| run_id | INTEGER | YES | 関連するランの永続ID |
| tag_id | INTEGER | NO | タグの永続ID |
| inserted_time | DOUBLE | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。行がDBに挿入された時刻 |
| tag_name | TEXT | YES | summary.protoのtagフィールド。ラン内で一意 |
| display_name | TEXT | YES | GUI表示用の名称（省略時はtag_nameがデフォルト） |
| plugin_name | TEXT | YES | ディスパッチ用のTensorBoardプラグイン名 |
| plugin_data | BLOB | YES | プラグインが必要とする任意のデータ |

**インデックス**:
- `TagIdIndex`: UNIQUE ON (tag_id)
- `TagRunNameIndex`: UNIQUE ON (run_id, tag_name) WHERE run_id IS NOT NULL AND tag_name IS NOT NULL

### 6. Runs

TensorFlowモデルのトレーニングまたはテストの1回分の実行を管理するテーブル。通常、特定のハイパーパラメータセットでの単一の試行を表す。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| experiment_id | INTEGER | YES | 関連する実験の永続ID |
| run_id | INTEGER | NO | ランの永続ID。SummaryWriterインスタンスと1:1対応 |
| inserted_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。行がDBに挿入された時刻（不変） |
| started_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。サマリー書き込み開始時刻（再起動時に更新） |
| finished_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。SummaryWriterリソース破棄時刻。非NULLになると不変扱い |
| run_name | TEXT | YES | ユーザー指定の文字列。実験内で一意 |

**インデックス**:
- `RunIdIndex`: UNIQUE ON (run_id)
- `RunNameIndex`: UNIQUE ON (experiment_id, run_name) WHERE run_name IS NOT NULL

### 7. Experiments

ランをグループ化する実験を管理するテーブル。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| user_id | INTEGER | YES | 関連するユーザーの永続ID |
| experiment_id | INTEGER | NO | 実験の永続ID |
| inserted_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。行がDBに挿入された時刻（不変） |
| started_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。MIN(experiment.started_time, run.started_time) |
| is_watching | INTEGER | YES | TensorBoard GUIでアクティブに閲覧中かどうかのブール値 |
| experiment_name | TEXT | YES | ユーザー指定の文字列。ユーザー内で一意 |

**インデックス**:
- `ExperimentIdIndex`: UNIQUE ON (experiment_id)
- `ExperimentNameIndex`: UNIQUE ON (user_id, experiment_name) WHERE experiment_name IS NOT NULL

### 8. Users

TensorBoardのユーザーを管理するテーブル。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| user_id | INTEGER | NO | ユーザーの永続ID |
| inserted_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。行がDBに挿入された時刻（不変） |
| user_name | TEXT | YES | 一意なユーザー名 |
| email | TEXT | YES | 一意なメールアドレス（オプション） |

**インデックス**:
- `UserIdIndex`: UNIQUE ON (user_id)
- `UserNameIndex`: UNIQUE ON (user_name) WHERE user_name IS NOT NULL
- `UserEmailIndex`: UNIQUE ON (email) WHERE email IS NOT NULL

### 9. Graphs

ランにおけるテンソルフローのグラフ定義を管理するテーブル。1つのランに対して1つのグラフのみ関連付けられる。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| run_id | INTEGER | YES | 関連するランの永続ID |
| graph_id | INTEGER | NO | グラフの永続ID |
| inserted_time | REAL | YES | マイクロ秒精度のFloat UNIXタイムスタンプ。行がDBに挿入された時刻 |
| graph_def | BLOB | YES | tf.GraphDefプロトのうちSQLで定義されていない残りの部分 |

**インデックス**:
- `GraphIdIndex`: UNIQUE ON (graph_id)
- `GraphRunIndex`: UNIQUE ON (run_id) WHERE run_id IS NOT NULL

### 10. Nodes

グラフ内の頂点（ノード）を管理するテーブル。各ノードはTensorFlowの計算グラフにおけるオペレーションを表す。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| graph_id | INTEGER | NO | 関連するグラフの永続ID |
| node_id | INTEGER | NO | グラフ内のノードID（0ベースのインデックス） |
| node_name | TEXT | YES | グラフ内で一意なノード名。NULLの場合はnode_def.nameプロトフィールドを参照 |
| op | TEXT | YES | tf.NodeDefプロトからコピーされたオペレーション名 |
| device | TEXT | YES | tf.NodeDefプロトからコピーされたデバイス名 |
| node_def | BLOB | YES | tf.NodeDefプロトのうちSQLで定義されていない残りの部分 |

**インデックス**:
- `NodeIdIndex`: UNIQUE ON (graph_id, node_id)
- `NodeNameIndex`: UNIQUE ON (graph_id, node_name) WHERE node_name IS NOT NULL

### 11. NodeInputs

グラフ内のノード間の有向エッジ（入力接続）を管理するテーブル。ノード間のテンソルの流れおよび制御依存関係を表現する。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| rowid | INTEGER | NO (PRIMARY KEY) | エフェメラルなB-tree ID |
| graph_id | INTEGER | NO | 関連するグラフの永続ID |
| node_id | INTEGER | NO | 入力先ノードのID（'to'頂点） |
| idx | INTEGER | NO | ノードの入力の順序を表すインデックス |
| input_node_id | INTEGER | NO | 入力元ノードのID（'from'頂点）。Nodes.node_idを参照 |
| input_node_idx | INTEGER | YES | 入力元ノードが出力する複数のテンソルのうちのインデックス。NULLは0として扱う |
| is_control | INTEGER | YES | 非ゼロの場合、制御依存関係を示す（テンソルが流れないエッジ）。NULLは0として扱う |

**インデックス**:
- `NodeInputsIndex`: UNIQUE ON (graph_id, node_id, idx)

## 備考

- データベースエンジンはSQLite（バージョン3.8.2以上が必要）を使用している
- アプリケーションID `0xfeedabee` がPRAGMAで設定される
- ユーザーバージョンは `0` に設定される
- テーブル作成には `CREATE TABLE IF NOT EXISTS` を使用しており、既存テーブルがある場合は何も行わない（冪等性あり）
- 永続IDはIdsテーブルで管理され、テーブル間で一意性が保証される設計となっている
- 外部キー制約はSQLスキーマ上では明示的に定義されていないが、アプリケーションロジックで参照整合性が維持される
- `tensorflow/core/lib/db/sqlite.h` にてSQLiteラッパークラス（`Sqlite`, `SqliteStatement`, `SqliteTransaction`, `SqliteLock`）が提供されており、メモリ安全性やトランザクション管理が実装されている
- 自動コミットモードがデフォルトであり、`SqliteTransaction` を使用するかWALモードを有効にしない限り、書き込みごとに4msのfsync()が発生する
