Appearance
DailyDataPerUnit テーブル(db2023)のスキーマ前提
概要
日別データ(台単位)を格納するテーブルは DatabaseTableConstants::DAILY_DATA(値: db2023)で、実際のテーブル名は環境ごとの WordPress テーブル接頭辞を付与した {$wpdb->prefix}db2023 となる(例: 接頭辞が wp_ の場合は wp_db2023)。
差枚(samai): マイナス値を数値(INT 型)で格納する場合、samai カラムは SIGNED である必要がある(INT 型で UNSIGNED のまま負の値を INSERT すると MySQL が 0 に変換する)。
DAY 列の型と日付形式
| 項目 | 正本 | 備考 |
|---|---|---|
| 列型 | date NOT NULL | DBML・ローカル・本番とも date( 時点で確認) |
| DB 格納・クエリバインド | YYYY-MM-DD | Repository は DateUtil::normalize_date_for_db() で統一 |
| アプリ内契約(Entity・インポート map キー等) | Y/n/j(例: 2025/1/10) | DateUtil::normalize_date_for_import()。読取時に Repository が正規化 |
DailyDataPerUnitRepository::insert_or_update_batch() は INSERT ... ON DUPLICATE KEY UPDATE を使用しており、一意キー (DAY, dainum, hall) が DB に存在する前提で動作する。本ドキュメントはその制約の確認方法と、未定義時の対応方針をまとめる。
kishu 列の意味とアプリ利用方針
物理列名 kishu は「表示名」と「取得元機種名」を区別していない。アプリでは次のように扱う。
| 概念 | 格納先 | アプリでの利用 |
|---|---|---|
| 表示用機種名 | db_kishu_master.name(kishu_id JOIN) | 読取・表示・集計の正本 |
| 取得元機種名(raw) | db2023.kishu 列 | 書込のみ(インポート時)。Repository 読取 SQL では t.kishu を参照しない |
既存行の db2023.kishu | 過去データ | 表示名が入っている場合がある。データ移行は行わない |
- インポート時:
DailyDataImportServiceがマッピング前の raw 名称をdb2023.kishuに書き込む(kishu_idは表示名ベースで解決)。 - 重複キー更新時:
kishu(取得元名)は incoming 値で上書きする。kishu_idは incoming が NULL のとき既存値を保持する(IFNULL(VALUES(kishu_id), kishu_id))。KishuIdResolverが解決失敗時に NULL を付与するため、既存の非 NULLkishu_idを誤って消さない。 - 読取時:
select_daily_data_per_unit.sql等はm.name AS kishuとし、Entity のget_kishu_name()は マスタの表示名 を返す(db2023.kishu列の値ではない)。 - SQL エイリアス
kishuは歴史的経緯により表示名を指す。物理列db2023.kishuとは別物である。
前提とする一意制約
- カラムの組み合わせ:
(DAY, dainum, hall) - 制約種別: UNIQUE KEY または PRIMARY KEY のいずれかがテーブルに定義されていること
RANGE パーティショニング
db2023 は PARTITION BY RANGE (YEAR(DAY))(年別 + p_future)とする。前提:
DAYはdate NOT NULL- すべての UNIQUE KEY / PRIMARY KEY が
DAYを含む(正本 DBML はUNIQUE KEY uk_day_dainum_hall (DAY, dainum, hall)。環境によっては同列の PRIMARY の場合あり)
年次パーティションの自動追加
月次 WP-Cron(DailyDataRangePartitionScheduler → DailyDataRangePartitionMaintainer)が 当年・翌年までの欠落年パーティション を REORGANIZE PARTITION p_future で冪等に追加する。
- 未パーティションのテーブルには触れない
p_futureの推定行数(InnoDBTABLE_ROWS)が 100,000 超のときは自動実行をスキップし、error_log に手動実施を促す- 年パーティション(
pYYYY)が 1 つも無い異常スキーマでは自動 REORGANIZE しない - 管理画面アクセス時(
admin_init、manage_options権限がある場合)に cron 登録が間引き同期される
閾値超過時・Cron 未発火時の手動例(2028 年分を追加する場合):
sql
ALTER TABLE `{prefix}db2023`
REORGANIZE PARTITION p_future INTO (
PARTITION p2028 VALUES LESS THAN (2029),
PARTITION p_future VALUES LESS THAN MAXVALUE
);スキーマ確認方法
本番または開発 DB に接続し、以下いずれかで制約の有無を確認する。以下ではテーブル名を {prefix}db2023 で表す。{prefix} は自環境の WordPress テーブル接頭辞(例: wp_)に読み替えて実行すること。
方法1: SHOW CREATE TABLE
sql
SHOW CREATE TABLE `{prefix}db2023`;出力に UNIQUE KEY または PRIMARY KEY で DAY, dainum, hall が含まれることを確認する。
方法2: information_schema
sql
SELECT `INDEX_NAME`, `COLUMN_NAME`, `NON_UNIQUE`
FROM information_schema.STATISTICS
WHERE `TABLE_SCHEMA` = DATABASE()
AND `TABLE_NAME` = '{prefix}db2023'
ORDER BY `INDEX_NAME`, `SEQ_IN_INDEX`;(DAY, dainum, hall) の組み合わせで一意制約(NON_UNIQUE = 0)または PRIMARY が存在するかを確認する。
関連コード
- SQL: core_src/Model/Sql/daily_data_per_unit/insert_or_update_batch.sql — 前提条件をコメントで明記
- Repository: DailyDataPerUnitRepository の
insert_or_update_batch()— 上記制約を前提とする旨を docblock で記載 - 年次パーティション: DailyDataRangePartitionScheduler / DailyDataRangePartitionMaintainer — 月次 WP-Cron による当年・翌年パーティション確保
制約が未定義の場合の対応
スキーマ確認の結果、(DAY, dainum, hall) の UNIQUE KEY / PRIMARY KEY が存在しない場合は、以下を確認したうえでマイグレーションを計画する。
1. 既存データの重複調査
重複行が存在すると UNIQUE 追加時にエラーになるため、事前に確認する。
sql
SELECT `DAY`, `dainum`, `hall`, COUNT(*) AS cnt
FROM `{prefix}db2023`
GROUP BY `DAY`, `dainum`, `hall`
HAVING COUNT(*) > 1;結果が 0 件であることを確認したうえで UNIQUE 追加を検討する。
2. UNIQUE KEY 追加のマイグレーション方針
- 重複が存在する場合は、データ整理(どれを残すかの方針と SQL)を別途検討する。
- 重複が存在しない場合、以下のように UNIQUE KEY を追加する。
sql
ALTER TABLE `{prefix}db2023`
ADD UNIQUE KEY uk_day_dainum_hall (`DAY`, `dainum`, `hall`);- 本番適用時はバックアップ取得・メンテナンス窓の確保を行う。
- スキーマ変更は WordPress 側の Installer(
core_src/Infrastructure/Database/のdbDelta)で配布する方針とし、本番での手動 DDL が必要な場合は当該*Installer.phpの定義と手順書をドキュメント化することを推奨する。
3. ドキュメントの記載
制約が未定義であることが判明した場合は、本ドキュメントの「前提とする一意制約」の直後に「現状は未定義。insert_or_update_batch の期待動作のため、制約追加を推奨する。」などの注記を追記し、上記「制約が未定義の場合の対応」セクションとあわせて運用する。