Skip to content

データベースのテーブル構成(ベース・_deleted・_history) ​

第2版作成 最終更新 (日本時間)
確認バージョン1.5.1.01.5.8.1

プリザンターのテーブルは、CodeDefiner がカラム定義(App_Data/Definitions/Definition_Column/*.json)から作ります。業務用のテーブルはどれも ベース・_deleted・_history の 3 つ組で作られ、論理削除では _deleted へ、バージョンアップを伴う更新では _history へ行をコピーします。

  • 1.5.8.1 の定義では、業務用のテーブルは 33 種類で、すべて 3 つ組です。3 つ組を持たないのは Quartz.NET 用の 11 テーブルだけで、これはクラスタリングを有効にしたときだけ作られます。
  • _deleted の列はベースと同じです。_history の列は、定義の History が 1 以上の列だけです。
  • _history の主キーは、定義の PkHistory が付いた列と Ver です。
  • 拡張項目を _history にコピーするのは Issues・Results・Depts・Groups・Users の 5 テーブルだけです。

CodeDefiner の全体の仕組みは CodeDefiner にあります。

対象バージョン

調査は 1.5.1.0 のソースで行い、このページの内容は 1.5.8.1 のソース(コミット fdcbb3f)で確かめ直しています。テーブルの数や主キーなど、1.5.8.1 で変わっている点はソースに合わせて書いています。

テーブルが作られる仕組み ​

CodeDefiner の _rds は、Def.TableNameCollection() で得たテーブル名ごとに ConfigureTableSet() を呼びます(TablesConfigurator.cs#L36-L79)。テーブル名はカラム定義の TableName を重複なしで集めたもので、ModelName が _Base で始まる共通定義は除かれます(Def.cs#L106-L116)。

ConfigureTableSet() の流れは次のとおりです(TablesConfigurator.cs#L151-L211)。

図を読み込み中…

  • NotUpdate(画面表示や計算用)、JoinTableName(他テーブルから JOIN する列)、Calc(C# で計算する列)の列と、今のスキーマバージョンで使わない列は、どのテーブルにも作られません。
  • 全テーブル共通の列(_Bases)は、定義の読み込み時に各テーブルへコピーされます。レコード系の共通列(_BaseItems)は ItemId が 1 以上のテーブルにだけコピーされます(Initializer.cs#L1050-L1090)。
  • 共通列の Ver は History が 21 なので(_Bases_Ver.json)、共通列を持つテーブルは必ず 3 つ組になります。
  • テーブルのすべての固有列に ExcludeBaseColumns が付いていると、共通列は作られません(TablesConfigurator.cs#L294-L322)。1.5.8.1 で該当するのは Quartz.NET のテーブルだけです。
共通列History物理列
Ver21作る
Comments100982作る
Creator100983作る
Updator100985作る
CreatedTime100989作る
UpdatedTime100990作る
VerUp100992作らない(NotUpdate)
Timestamp100993作らない(NotUpdate)

History の値は、_history に含めるかどうかの判定と、_history の列の並び順の両方に使われます。

テーブルの一覧(1.5.8.1) ​

業務用のテーブル(3 つ組) ​

テーブル内容テーブル内容
AutoNumberings自動採番Orders並び順
BackgroundJobsバックグラウンドジョブOutgoingMails送信メール
Binaries添付ファイル・画像Parametersパラメータ
Dashboardsダッシュボード(レコード系)Passkeysパスキー
DemosデモPermissionsアクセス権
Depts組織Registrationsユーザー登録
Extensions拡張機能ReminderSchedulesリマインダーのスケジュール
GroupChildrenグループの子グループResults記録テーブル(レコード系)
GroupMembersグループのメンバーScimTokensSCIM トークン
GroupsグループSessionsセッション
Issues期限付きテーブル(レコード系)Sitesサイト(レコード系)
Items全レコード共通の親Statuses状態管理
LinksリンクSysLogsシステムログ
LoginKeysログインキーTenantQuotaUsagesテナントの使用量
MailAddressesメールアドレスTenantsテナント
McpLogsMCP のログUsersユーザー
WikisWiki(レコード系)

調査時点(1.5.1.0)の 28 テーブルに加えて、1.5.8.1 の定義には BackgroundJobs、McpLogs、Parameters、ScimTokens、TenantQuotaUsages があります。レコード系(ItemId が 1 以上)は Sites・Results・Issues・Wikis・Dashboards の 5 つで、どれも Items と ReferenceId で結び付きます。

Quartz.NET のテーブル ​

QRTZ_BLOB_TRIGGERS、QRTZ_CALENDARS、QRTZ_CRON_TRIGGERS、QRTZ_FIRED_TRIGGERS、QRTZ_JOB_DETAILS、QRTZ_LOCKS、QRTZ_PAUSED_TRIGGER_GRPS、QRTZ_SCHEDULER_STATE、QRTZ_SIMPLE_TRIGGERS、QRTZ_SIMPROP_TRIGGERS、QRTZ_TRIGGERS の 11 テーブルです。

  • Quartz.json の Clustering.Enabled(既定 false)が true のときだけ作られます(TablesConfigurator.cs#L15-L20、Quartz.json)。
  • 固有列の History がなく、共通列も作らないので、_deleted と _history はありません。
  • PostgreSQL ではテーブル名と列名が小文字になります(qrtz_blob_triggers など。TablesConfigurator.cs#L22-L34)。

物理テーブルは 33 × 3 = 99 で、クラスタリングを有効にすると 110 になります。

3 つのテーブルの列の違い ​

テーブル列並び順
ベース物理列すべてNo 順
_deletedベースと同じNo 順
_history物理列のうち History が 1 以上History 順

1.5.8.1 の定義では、ScimTokens 以外のテーブルは物理列すべてに History が付いているので、3 つのテーブルの列の構成は同じです。

ScimTokens だけは固有列(ScimTokenId、TenantId、UserId、TokenHash、TokenPrefix、Disabled、ExpiresTime、LastUsedTime)に History が無く、ScimTokens_history には共通列の 6 列だけが作られます(ScimTokens_TokenHash.json)。一方、ScimTokensCopyToStatement は固有列も含めて _history へ INSERT する SQL を作るので(Rds.cs#L14669-L14692)、バージョンアップを伴う更新(ScimTokenModel.cs#L359-L365)が行われると、存在しない列への INSERT になります。

新しい列の定義で History を省略すると、既定値の 0 になって _history から外れます。

主キー ​

ベースと _deleted の主キーは、定義の Pk が付いた列です。_history の主キーは、History と PkHistory の両方が付いた列です(Indexes.cs#L190-L212)。共通列の Ver は PkHistory が 3 なので、すべての _history の主キーに入ります。

_history の主キーテーブル
固有の ID など + VerBackgroundJobs、Binaries、Dashboards、Depts、GroupChildren、GroupMembers、Groups、Issues、Items、MailAddresses、OutgoingMails、Parameters、Permissions、Registrations、Results、Sites、SysLogs、TenantQuotaUsages、Tenants、Users、Wikis
Ver だけAutoNumberings、Demos、Extensions、Links、LoginKeys、McpLogs、Orders、Passkeys、ReminderSchedules、ScimTokens、Sessions、Statuses

Ver だけのテーブルは、別のレコードの同じバージョンの履歴を 2 件入れられません。

Tenants_history の主キーは、1.5.8.1 の定義では TenantId に PkHistory: 1 があるので (TenantId, Ver) です(Tenants_TenantId.json)。調査時点(1.5.1.0)の定義には PkHistory が無く、主キーは (Ver) だけでした。

_deleted の主キーはベースと同じなので、同じ ID の行は 1 件しか入りません。

SQL でのテーブルの選び方 ​

SQL を組み立てるときは、Sqls.TableTypes でベース・_deleted・_history のどれを使うかを選びます(Sqls.cs#L14-L23)。

値対象
Normalベース
Deleted_deleted
History / HistoryWithoutFlag_history
NormalAndDeletedベース + _deleted の UNION
NormalAndHistoryベース + _history の UNION
All3 つの UNION

各 SQL 文は TableBracket、HistoryTableBracket、DeletedTableBracket の 3 つのテーブル名を持っていて(SqlStatement.cs#L13-L15)、TableTypes に応じてどれかを使います。

論理削除・復元・履歴のコピー ​

操作SQL
論理削除(Delete{テーブル}Statement)ベースの Updator・UpdatedTime を更新 → _deleted に INSERT ... SELECT → ベースから DELETE
復元(Restore{テーブル}Statement)_deleted の Updator・UpdatedTime を更新 → ベースに INSERT ... SELECT → _deleted から DELETE
履歴のコピー({テーブル}CopyToStatement)更新前の行を _history に INSERT ... SELECT してから Ver を 1 増やす

論理削除と復元の SQL は Rds.cs に文字列で書かれています(Issues の例: Rds.cs#L20027、Rds.cs#L21824)。履歴のコピーはバージョンアップを伴う更新のときだけで、Tenants の例は TenantModel.cs#L979-L986 です。SQL だけで同じ操作をする例は 内部 CRUD を SQL で実現 にあります。

レコードを削除したときに動くテーブル ​

Issues の論理削除では、Items、Binaries、Issues の行が _deleted に移ります(IssueModel.cs#L2464-L2510)。Links の行は移らずにベースに残るので、復元の対象にも入っていません(IssueUtilities.cs#L6099-L6131)。

Links と Permissions に残った行のうち、参照先が Items にも Items_deleted にも無いものは、BackgroundService.json の DeleteUnusedRecord(既定 false)を true にすると、DeleteUnusedRecordTime(既定 03:00)に DeleteUnusedRecordChunkSize(既定 1000)件ずつ消されます(DeleteUnusedRecordTimer.cs#L56-L104、BackgroundService.json#L15-L17)。SQL は DeleteByUnusedReferenceId.sql で、Items と Items_deleted のテーブル名が直接書かれています(DeleteByUnusedReferenceId.sql(SQL Server))。

画面・API から削除・復元できないテーブル ​

Rds.cs には全テーブルの論理削除・復元の SQL がありますが、モデル側でそれを呼ぶのは一部のテーブルだけです。

  • SysLogs は SysLogModel.Delete() で SysLogs_deleted に移せますが(SysLogModel.cs#L2513)、復元するメソッドはありません。
  • AutoNumberings、GroupChildren、GroupMembers、Links、LoginKeys、Orders、Permissions、ReminderSchedules、Sessions、Statuses は、モデル自身に削除・復元のメソッドがなく、親の操作に付随して書き換えられます。

拡張項目と _history ​

操作拡張項目の列の扱い対象
履歴のコピー(CopyTo)columnNames で渡された列を追加するIssues、Results、Depts、Groups、Users だけ
論理削除・復元DeleteParams() が ColumnUtilities.ExtendedColumns() で拡張項目の列を足す全テーブル
  • CopyTo で拡張項目の列を足すコードは、Rds_CopyToStatementColums_Extended.json の Include に書かれた 5 テーブルにだけ生成されます(Rds_CopyToStatementColums_Extended.json)。たとえば TenantsCopyToStatement は引数に columnNames を受け取りますが、使っていません(Rds.cs#L14860)。
  • 論理削除・復元の列は DeleteParams() で実行時に決まります(Rds.cs#L20167、ColumnUtilities.cs#L17-L25)。
  • 標準の拡張項目(ClassA〜Z など)が定義されるのは Depts・Groups・Users・Issues・Results の 5 テーブルなので(Def.cs#L6494-L6534)、既定の構成ではコピー漏れは起きません。
  • 商用ライセンスで使える ExtendedColumnsSet は、TableName に任意のテーブルを書けます(Def.cs#L6550-L6578)。5 テーブル以外に列を足すと、_history にも列は作られますが、履歴のコピーでは値が入らず NULL になります。論理削除・復元では値は移ります。
  • 拡張項目を増やしたときの SQL Server の行サイズ(1 行 8,060 バイト)の見積もりと、実 DB の現状を確かめる方法は SQL Server の行サイズの見積もりと現状診断 にあります。

標準パターンから外れている箇所 ​

TableTypes を使わずにテーブル名を直接書いている主な箇所です。

箇所内容
DeleteByUnusedReferenceId.sqlItems と Items_deleted を直接参照(上述)
ItemUtilities の Items への JOINレコード系 5 テーブルのときだけ、TableTypes に応じて Items・Items_history・Items_deleted を選ぶ
Indexes.cs の全文検索_deleted のときだけ Items_deleted・Binaries_deleted を見る。ゴミ箱と履歴の一覧の検索が LIKE になる話は 検索機能の内部実装 を参照
権限判定の SQL(CanRead.sql など)ベースのテーブルだけを見る

関連ページ ​

変更履歴

第2版データベースのテーブル構成に、拡張項目と行サイズ上限の関係を追記
第1版セッションの仕組みとデータベースのテーブル構成の解説を追加し、性能とスケールアウトの説明を修正