Skip to content

機種マスタ移行ロードマップ(Issue #2135)

親 Issue: #2135 機種名の文字列保持をマスタID参照に改修する

背景

現状、機種は各テーブルの kishu 列に文字列で保持され、表示用への変換は db_kishu_display_mapping と「登録データに反映」による一括 UPDATE で同期している。機種名リネーム後に参照元だけ古い名称が残る、反映対象テーブルの都度追加、表記ゆれによる集計複雑化が課題となる。

フェーズ一覧

フェーズ内容実装単位
1マスタテーブル db_kishu_master の設計・Installer・DBML・ドキュメント整備本 PR(KishuMasterInstaller
2既存 kishu 文字列のマスタへの初期投入、インポート時の未登録機種の自動マスタ登録#2137
3各業務テーブルへ kishu_id 列追加・バックフィル(文字列と並行保持)#2138
4参照を kishu_id に切り替え、db_kishu_display_mapping の整理(db2023.kishu は確認用に永続保持)#2139

移行対象テーブル(文字列 kishu 保持)

テーブル(suffix)現状のキー列フェーズ3以降
db2023kishukishu_id 追加。kishu は raw 名称確認列として永続保持(DROP しない)
db_daily_article_kishu_single_day_summarykishukishu_id 追加
db_daily_article_kishu_count_deltakishukishu_id 追加
db_birthday_kishukishukishu_id 追加
db_kishu_display_mappingdata_kishu / display_kishuマスタ・別名テーブルへの取り込み検討(フェーズ4)
KishuIndexName別途優先度整理

移行期間中の二重管理方針(フェーズ3)

  • 保持: 既存の文字列列(kishu)と新規 kishu_id を並行して保持する。
  • 書き込み: 新規・更新時は kishu_id と文字列の両方を書き込む(バックフィル完了後もフェーズ3中は維持)。
  • 読み取り: フェーズ3中は表示・集計の参照は従来どおり文字列 kishu を優先する。kishu_id が NULL の行はバックフィル対象として扱う。
  • 検証: バックフィル後、同一行で kishu とマスタ name の突合が一致することを確認してからフェーズ4へ進む。

フェーズ4完了後の想定

  • 業務テーブルは kishu_id で機種を参照し、表示名はマスタ(または別名テーブル)から解決する。
  • db2023.kishu は DROP しない。インポート元 raw 名称(マッピング変換前)を確認用データとして永続保持する。アプリケーションからは参照しない(PR #2285)。
  • summary / delta / birthday_kishu 等の他業務テーブルについては、フェーズ4で kishu 文字列列の廃止を検討する(db2023 は対象外)。
  • db_kishu_display_mapping の「登録データに反映」一括 UPDATE は不要になる方向で整理する(#2134 系の同期対象拡張はマスタ移行完了後に見直し)。

非スコープ(#2135 全体)

  • #2134 の db_birthday_kishu への「登録データに反映」拡張(別 PR 可)
  • マスタ移行完了前の既存マッピング UI の即時削除

関連 Issue

  • #1203(機種表示マッピング)
  • #2076(機種別サマリ)
  • #2134(登録データ反映で summary / delta を同期)

マイグレーション手順(フェーズ1)

  1. 管理画面初回読み込み時(admin_init)に AdminDatabaseInstaller::ensure_all() が実行され、KishuMasterInstaller::install() が走る。
  2. VersionedTableInstallerTrait により、db_kishu_master が未作成、またはインストール済みバージョンが current 未満、または必須カラムの不足・禁止カラムの存在など現在の実装で検証している範囲で不一致がある場合に dbDelta が実行され、必要な作成・更新を行ったうえでオプション kishu_master_db_version1 に更新する。
  3. 既にテーブルが存在し、必要なカラム構成が満たされており、かつバージョン更新も不要な場合は即 return(冪等)。

マイグレーション手順(フェーズ3 / Issue #2138)

前提: フェーズ2(db_kishu_master へのシード・インポート時自動登録)が完了していること。

  1. 列追加(Installer): init で次が冪等実行される。
    • DailyArticleKishuSummaryInstaller(v4)
    • DailyArticleKishuCountDeltaInstaller(v2)
    • DailyDataKishuIdInstallerdb2023kishu_id のみ追加)
    • BirthdayKishuInstallerdb_birthday_kishu
  2. バックフィル: 格納済みの文字列 kishudb_kishu_master.name を突合し kishu_id を UPDATE。未登録名は先に upsert_by_names でマスタへ投入。
    • 事前(db_birthday_kishu のみ): wp slot-kouryaku kishu-master-seed rundb_birthday_kishu.kishu の DISTINCT 名称を db_kishu_master へ INSERT IGNORE(Issue #2290)。kishu-id-backfill run 実行前に推奨。
    • 小テーブル(summary / delta / birthday_kishu): wp slot-kouryaku kishu-id-backfill run(テーブル指定なしで secondary のみ)
    • db2023: wp slot-kouryaku kishu-id-backfill run --table=daily_data --batch-size=5000 でバッチ繰り返し
  3. 検証: wp slot-kouryaku kishu-id-backfill verifykishu_id IS NULL 残件数を確認。0 件が理想。db_birthday_kishu のマスタ未登録名は次で確認できる(0 件が理想):
    sql
    SELECT COUNT(DISTINCT TRIM(bk.kishu))
    FROM wp_db_birthday_kishu bk
    LEFT JOIN wp_db_kishu_master m ON TRIM(bk.kishu) = m.name AND m.is_active = 1
    WHERE TRIM(bk.kishu) != '' AND m.id IS NULL;
  4. 以降の書き込み: インポート・サマリ再計算・誕生日 CRUD・マッピング反映で kishu_id を書き込む。db2023 には raw 名称を kishu 列にも保存(確認用)。読み取りは kishu_id JOIN マスタを優先。

マイグレーション手順(フェーズ4 / Issue #2139)

正本ドキュメント: 本ファイル。Issue #2139 本文のロードマップと同期すること。

前提: フェーズ3(4業務テーブルへの kishu_id 列追加・バックフィル CLI)が完了していること。PR #2273(db_kishu_display_mappingkishu_id FK 化)マージ済み。

staging / 本番共通の注意(collation)

  • 既存 db_kishu_display_mapping(2023年作成)は utf8mb4_unicode_ci のことが多い。
  • 新規 db_kishu_master$wpdb->get_charset_collate() 由来(WP 6.x では utf8mb4_unicode_520_ci 等)になりやすい。
  • display_kishu = master.name の列同士 JOIN は MySQL #1267(collation 混在)で失敗し、kishu_id バックフィルが進まない。
  • 対応: PR #2279 以降、KishuDisplayMappingInstaller のバックフィル JOIN に COLLATE を付与。

「機種マスタへ投入」の件数について

  • マッピング 行数(例: 439)と「処理 N 件」は一致しない場合がある。
  • 「処理 N 件」= display_kishu正規化後ユニーク件数(複数 data_kishu → 同一 display_kishu は1件に集約)。
  • 「新規 M 件」= マスタに未登録だった名称のみ INSERT IGNORE

本番一括デプロイ推奨順(フェーズ1〜4 を一度に入れる場合)

  1. コードデプロイ + PHP-DI キャッシュ削除core_src/config/di.php 変更時)
  2. 管理画面を1回開くdb_kishu_master テーブル作成(KishuMasterInstaller
  3. 機種表示マッピング管理画面で「機種マスタへ投入」display_kishudb_kishu_master に upsert(バックフィル前提。自動ではない)
  4. 未マッチ確認(SQL)display_kishumaster.name が突合できること(COLLATE 付き JOIN で 0 件が理想)
  5. kishu_display_mapping_backfill_attempts 確認 — 5 到達時は wp option delete kishu_display_mapping_backfill_attempts 後に再試行
  6. 管理画面または任意ページを再読み込みKishuDisplayMappingInstallerkishu_id バックフィル + display_kishu DROP(kishu_display_mapping_db_version = 2
  7. 4業務テーブルの kishu_id バックフィルwp slot-kouryaku kishu-id-backfill run(#2138)。db_birthday_kishu については事前に wp slot-kouryaku kishu-master-seed run(#2290)を推奨。
  8. 動作確認 — 日別インポート・マッピング保存同期・ランキング表示等

デプロイ直後の注意: 手順3完了前に一般公開すると、init でバックフィル失敗が backfill_attempts に蓄積され得る。可能なら手順2〜6を連続実施する。

Installer 実行タイミング(参考)

Installerトリガー
KishuDisplayMappingInstaller(バックフィル含む)init priority 0 + admin_init
KishuMasterInstaller(テーブル作成のみ)admin_init のみ
マスタデータ投入管理画面「機種マスタへ投入」(手動)

staging でバックフィルが止まったときの手動復旧(コード修正前)

sql
UPDATE wp_db_kishu_display_mapping AS m
INNER JOIN wp_db_kishu_master AS km
  ON km.name = m.display_kishu COLLATE utf8mb4_unicode_520_ci
  AND km.is_active = 1
SET m.kishu_id = km.id
WHERE (m.kishu_id IS NULL OR m.kishu_id = 0)
  AND m.display_kishu IS NOT NULL AND m.display_kishu != '';

その後 wp option delete kishu_display_mapping_backfill_attempts → ページ再読み込みで display_kishu DROP を Installer に任せる。