Skip to content

db2023 台別データ 読み取りパフォーマンス調査(Issue #2293)

参考 / 調査メモ: 2026-06 時点の性能調査記録です。現役の本番作業手順ではありません。現在のテーブル定義は カスタムアプリケーションテーブル と各 Installer を優先してください。

目的

wp_db2023DatabaseTableConstants::DAILY_DATA)の読み取りパフォーマンスを調査し、インデックス見直し・DAY 型変換・MySQL パーティショニング・年別テーブル分割の各案を比較する。本ドキュメントは 調査/設計 の成果物であり、スキーマ変更の実装は Issue #2135(kishu_id バックフィル)完了後を推奨する。Issue #2341 の本番導入手順は db2023 RANGE パーティショニング本番導入手順 を参照。

現状: 本ドキュメント内の kishu_id バックフィル記述は、2026-06 時点の調査メモです。機種マスタ移行に伴う本番バックフィルは完了済みであり、現状の本番運用で追加対応する前提ではありません。

調査環境

項目
環境Local(slotkouryaku.local
DBMySQL(Local run: 5pYRuxwSB
テーブルwp_db2023
調査日2026-06-12

現状スキーマ(ローカル DB)

sql
CREATE TABLE `wp_db2023` (
  `DAY` date NOT NULL,
  `kishu` varchar(255) NOT NULL,
  `dainum` varchar(255) NOT NULL,
  `kaiten` int(11) NOT NULL,
  `samai` int(11) NOT NULL,
  `BB` int(11) NOT NULL,
  `RB` int(11) NOT NULL,
  `hall` varchar(255) NOT NULL,
  `kishu_id` bigint(20) unsigned DEFAULT NULL,
  PRIMARY KEY (`DAY`,`dainum`,`hall`) USING BTREE,
  KEY `idx_kishu_id` (`kishu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

ローカルと Issue 記載の差異

項目Issue #2293 記載(本番想定)ローカル実測
DAYvarchar(10)Y/n/j 形式date 型、YYYY-MM-DD 格納
日付リテラル'2025/1/10''2026-03-16' 等(MySQL が date に解釈)

注意(調査当時): Issue #2293 時点では本番が varchar の可能性があった。2026-07 再確認では本番も dateであり、varchar → date の DDL 移行は不要。DBML は当初から date を正としている。

テーブル規模(ローカル)

指標
総行数1,439,926
データサイズ約 151 MB
インデックスサイズ約 64 MB
合計約 215 MB
日付範囲2022-07-29 〜 2026-03-16
1 日あたり行数(直近)約 519〜911 行/日

用途別の読み取りパターン

用途読み取り範囲主要メソッドSQL パターン
日別記事・台別ランキング直近 3 日(DAYS_BACK_FOR_RANKING_DATA = 2select_daily_data_per_unit_by_ymdWHERE DAY IN (3日) → PHP で hall フィルタ
期間差枚サマリー(SC-010)最大 366 日select_daily_data_group_by_day_and_hall_and_kishu_by_ymdWHERE DAY IN (最大366日) → PHP で hall・kishu フィルタ
期間機種別差枚ランキング(SC-016)最大 366 日同上WHERE DAY IN (最大366日) → PHP で hall フィルタ

機種別ランキングは db_daily_article_kishu_single_day_summary を優先参照(Issue #2076)。台別 raw(db2023)の直接参照は上記 3 用途が中心。

kishu_id バックフィル状況(Issue #2135)

sql
SELECT COUNT(*) AS total,
       SUM(kishu_id IS NULL) AS null_count,
       SUM(kishu_id IS NOT NULL) AS filled_count
FROM wp_db2023;
環境totalnull_countfilled_count
ローカル(2026-06-12)1,439,9261,439,9260

調査時点のローカルでは kishu_id が全行 NULL。現行 SQL は INNER JOIN wp_db_kishu_master ON t.kishu_id = m.id を前提とするため、JOIN 付きクエリは 0 件 を返す状態だった。本番のバックフィル完了状況確認は当時の移行作業向けメモであり、現状の本番追加対応を示すものではない。

依存関係: 大規模 ALTER(パーティション追加・型変更)と kishu_id バックフィルが重複すると全行スキャンが二重化する。調査は先行可、実装は #2135 完了後を推奨

EXPLAIN 結果

1. 台別ランキング(直近 3 日)— select_daily_data_per_unit

対象日: 2026-03-14, 2026-03-15, 2026-03-16(実データ 1,949 行)

kishu_master JOIN あり(現行アプリ SQL)

id  select_type  table  type   key       rows     Extra
1   SIMPLE       m      index  uk_name   1        Using index; Using temporary; Using filesort
1   SIMPLE       t      range  PRIMARY   3        Using where; Using join buffer (Block Nested Loop)

kishu_id が NULL のため JOIN が成立せず、推定 rows が実態と乖離。

JOIN なし(テーブル単体の読み取り性能)

id  select_type  table  type   key       rows     Extra
1   SIMPLE       t      range  PRIMARY   1949     Using where; Using filesort

実行時間(profiling): 約 0.012 秒(1,949 行取得)

2. 期間集計(SC-010 / SC-016)— select_daily_data_group_by_day_and_hall_and_kishu

3 日 GROUP BY(JOIN なし)

type=range, key=PRIMARY, rows=1949, Extra=Using where; Using temporary

年跨ぎ 121 日(2024-12-01 〜 2025-03-31)

type=range, key=PRIMARY, rows=108053(推定), 実際の取得行数=108,053
Extra=Using where; Using temporary

最大 365 日(2025-03-17 〜 2026-03-16)

type=range, key=PRIMARY, rows=55480(推定), 実際の取得行数=303,586
Extra=Using where; Using temporary

3. DAY + hall クエリ — DailyDataRepository

WHERE DAY = '2026-03-16' AND hall = 'アイランド秋葉原':

type=ref, key=PRIMARY, rows=911, Extra=Using where

PRIMARY KEY (DAY, dainum, hall) の先頭列 DAY で絞り込み後、hall は 3 列目のためインデックス上では完全カバーされない。

コード影響範囲調査

DAY バインド形式(date 列)

進捗(Issue #2297): 本番・ローカルとも DAYdate 型。アプリは Repository 境界で DateUtil::normalize_date_for_db()Y-m-d)に統一(暗黙変換依存を解消)。varchar → date の DDL 移行は不要。

レイヤファイル影響
インポートDailyDataImportService行の DAY はアプリ内で Y/n/j のまま。INSERT 時に Repository が Y-m-d
リポジトリDailyDataPerUnitRepositoryY-m-d でバインド。Entity 読取は Y/n/j に正規化
リポジトリDailyDataRepositoryY-m-d でバインド
ユーティリティDateUtil::normalize_date_for_importアプリ内契約用。DB 用は normalize_date_for_db
EntityDailyDataPerUnitEntityアプリ契約は Y/n/j(読取時に正規化)

(DAY, hall) 複合インデックスの効果

クエリパターンSQL に hall 条件(DAY, hall) の効果
select_daily_data_per_unit(台別ランキング)なし(PHP フィルタ) — 3 日分全ホール取得のため
select_daily_data_group_by_*(SC-010/016)なし(PHP フィルタ) — 最大 366 日×全ホール取得
DailyDataRepository::get_daily_data_by_kishuあり(DAY = ? AND hall = ? — PRIMARY の DAY 先頭で部分利用、専用索引で hall 絞り込み改善の余地
select_count_by_day_and_titleオプション(hall IN (...)(hall 指定時のみ)
delete_by_date_and_hall / batch_delete_by_date_hall_pairsあり中〜高

結論: (DAY, hall) インデックス単体では SC-010/SC-016 のボトルネック(全ホール DB 転送)は解消しない。リポジトリ/SQL に hall 条件を追加するアプリ変更とセットで検討する価値がある。

Period 系サービスの全ホール取得(確認済み)

  • PeriodKishuSamaiRankingService::get_ranking()select_daily_data_group_by_day_and_hall_and_kishu_by_ymd($ymd_list) で全ホール取得後、if (!in_array($dto->hall, $halls, true)) で PHP フィルタ
  • PeriodSamaiSummaryService::get_summary() — 同上取得後、array_filter で hall・kishu フィルタ
  • DailyArticleResultServiceselect_daily_data_per_unit_by_ymd で 3 日分全ホール取得後、PHP で hall フィルタ

改善案の比較

概要年跨ぎ対応アプリ変更運用コストローカル調査所見
A: インデックス追加(DAY, hall) 複合インデックスそのまま不要(ただし効果限定)SC-010/016 には効果薄。DailyDataRepository 系には有効
A': SQL に hall 条件追加リポジトリに hall パラメータを追加そのまま必要(Interface・Service・SQL)転送量削減に最も効果的(1 ホール指定時)
B: MySQL パーティショニング年別 RANGE パーティションMySQL が自動横断不要低〜中DAY が date 型なら PARTITION BY RANGE (YEAR(DAY)) が適用可能。varchar 時は式パーティションが必要
C: 年別テーブル分割db_daily_data_{year}リポジトリで UNION必要(ルーティング)高(毎年作業)年跨ぎクエリの UNION コスト・アプリ複雑化が大きい

案 B のパーティション設計(DAY が date 型の場合)

sql
ALTER TABLE wp_db2023
PARTITION BY RANGE (YEAR(`DAY`)) (
  PARTITION p2022 VALUES LESS THAN (2023),
  PARTITION p2023 VALUES LESS THAN (2024),
  PARTITION p2024 VALUES LESS THAN (2025),
  PARTITION p2025 VALUES LESS THAN (2026),
  PARTITION p2026 VALUES LESS THAN (2027),
  PARTITION p_future VALUES LESS THAN MAXVALUE
);
  • WHERE DAY IN (...) は該当パーティションのみスキャン
  • 年跨ぎ期間(例: 2024-12 〜 2025-03)は複数パーティション横断だが、アプリ変更なし
  • 大テーブル ALTER は pt-online-schema-change 等のオンライン DDL を検討

案 B の制約(DAY が varchar の場合)

式ベースパーティションが必要:

sql
PARTITION BY RANGE (YEAR(STR_TO_DATE(`DAY`, '%Y/%c/%e')))
  • パーティション pruning が式に依存し、プランナの挙動が複雑化
  • DAY を date 型へ正規化してからパーティション適用が望ましい

推奨実装順序

現時点の推奨: 案 B(MySQL パーティショニング) を中長期の主軸とし、短期では 案 A'(SQL hall 条件追加) で SC-010/SC-016 の DB 転送量を削減する。案 C(年別テーブル分割)は運用コスト・アプリ変更量の観点から優先度を下げる。

DoD 計測基準との対照

docs/performance/README.md の目標値:

指標目標(2 ホール)本調査での観測
Query Count15 以下本調査対象外(別途 run-performance-test.sh で計測)
Execution Time0.05 秒以下3 日 select_daily_data_per_unit(JOIN なし): 約 0.012 秒 ✓
Memory Usage2 MB 以下本調査対象外
EXPLAIN rows 改善改善していること366 日 GROUP BY: 推定 55,480 / 実 303,586 行 — パーティション+hall 条件で削減見込み

次のアクション(実装 Issue 用)

  1. 本番: SHOW CREATE TABLE wp_db2023kishu_id NULL 件数を確認
  2. #2135 完了後: DailyDataPerUnitRepository に hall オプション引数を追加する設計 Issue を起票
  3. #2135 完了後: DAY 型統一 + RANGE パーティション追加のマイグレーションを db2023 RANGE パーティショニング本番導入手順 に従って実施(Issue #2341)
  4. 計測: 変更前後で scripts/run-performance-test.sh および SC-010/016 の代表クエリで EXPLAIN・実行時間を比較

再現用 SQL(ローカル)

bash
# Local MySQL ソケット例(環境によりパスが異なる)
MYSQL_SOCK="/Users/a/Library/Application Support/Local/run/<site-id>/mysql/mysqld.sock"

# スキーマ・行数
mysql -uroot -proot -S "$MYSQL_SOCK" local -e "SHOW CREATE TABLE wp_db2023;"
mysql -uroot -proot -S "$MYSQL_SOCK" local -e "SELECT COUNT(*) FROM wp_db2023;"

# 3 日クエリ EXPLAIN
mysql -uroot -proot -S "$MYSQL_SOCK" local -e "
EXPLAIN SELECT t.\`DAY\`, t.kishu, t.dainum, t.kaiten, t.samai, t.BB, t.RB, t.hall
FROM wp_db2023 AS t
WHERE t.\`DAY\` IN ('2026-03-14','2026-03-15','2026-03-16')
ORDER BY t.dainum ASC, t.\`DAY\` ASC;
"

kishu_id バックフィル完了後は、JOIN 付きクエリ(select_daily_data_per_unit.sql 相当)でも EXPLAIN を再取得すること。

参照