# TeamWorks 様 確認事項（第9回）

**作成: 2026-09-17 改訂（初版 2026-09-15 / 統合 2026-09-16）/ 作成者: DFA Robotics**

> ★**2026-09-17（2回目）の改訂点**★:
> ★★**テスト環境のDBに入っているデータは、当方（DFA）が入れた検証用のダミーデータで
> ありました**★★。★つきましては「行の中身」を根拠にしていた記述を、**取り下げるか、
> 当方の検証用データでの観測である旨を明記する**形に改めております★
> / ★2章は実データの話を削り、**仕様の確認のみ**に縮めました（Q2-2 は取り下げ）★
> / ★5章（面積の単位）は**弊社で「㎡」と確定**しましたので、設問（Q5-1）を取り下げました★
> / ★8章 Q8-3 は「固定値」ではなく**「運用上の下限・上限・変更の頻度」**を伺う形に改めました★
> / ★10章（DB更新用アカウント）は**すでに権限が発行されておりました**。当方の確認漏れです。
> ご依頼を取り下げました★
> / ★11章 Q11-1（実際の清掃開始時刻）は **お伺いする内容を改めました**。
> 「どこにありますか」ではなく ★**「`started_at` を使って実装してよろしいでしょうか」**★ という
> 確認に変えております。あわせて **Q11-4** を新たに立てました★
>
> ★**2026-09-17（1回目）の改訂点**★: ★索引（1章）はご対応中と伺いましたので、ご依頼を取り下げ
> 参考情報に改めました★ / ★規模の前提を「施設200件（仮置き）」から「ロボット30台未満
> （弊社把握）」に置き直しました（1章・2-4）★ / ★台数・施設数の設問（旧 Q8-1 / Q8-2）を
> 取り下げました（弊社側で決めるべきことのため）★

> ★**本書は、第9回確認事項に、DB接続経路についての申し送り（お願い3件・確認6問）を
> 統合したものです。**★
> ★**別便は出しません。第9回として1通にまとめてお送りいたします。統合した内容は12章です。**★

## はじめに

★**第8回（2026-09-11）にはご回答をいただき、ありがとうございました。**★
★**いただいた回答をもとに、タイムゾーン・エラー率・エリア別完了率の実装を直しております。**★

★**第8回の Q4（サマリの率・分子・分母の関係）は「多いので後で回答」との留保をいただいた
ままです。取り下げておりませんので、引き続きお願いいたします（本書の3章に再掲します）。**★

そのうえで、★**テスト環境のDBに接続して実測を行ったところ、確認事項が新たに発生しました。**★

## ★★おことわり — テスト環境のデータは当方が入れたものでした★★

★**本書の初版（2026-09-15）では、テスト環境のDBの「行の中身」を根拠にした記述がございました。**★
★★**その後、当方で確認いたしましたところ、テスト環境に入っているデータは当方（DFA）が
開発用に投入した検証用のダミーデータでした。**★★
★**そのため、行数・値の分布・特定のテーブルが0行であること等を根拠にした指摘は、
貴社のバッチや収集処理の挙動を示すものではありませんでした。**★

★**本改訂では、これらを次のように仕分けております。**★

| 種別 | 例 | 本書での扱い |
|---|---|---|
| ★構造から分かること★ | DDL / `SHOW CREATE TABLE` / 索引の有無 / `possible_keys = null` / カラムの有無・型 / サーバー変数 / 権限 | ★そのまま根拠として記載しております★ |
| ★★行の中身から読み取っていたこと★★ | 行数・値の分布・「全件が同じ値」「0行である」等 | ★★取り下げるか、「当方の検証用データでの観測です」と明記しております★★ |

★**紛らわしいことを申し上げ、失礼いたしました。**★

## 本書の構成

★**索引の件については、ご対応中と伺いました。**★
★**つきましては1章はご依頼を取り下げ、参考情報に改めております（詳細は1章の冒頭に記しました）。**★

★**そのうえで本書の中心は、12章（DB接続経路）です。**★
★**12章は期限が「ステージングに実データが入る前」という性質のもので、過ぎますと
作り直しになります。**★

★**あわせて、3章・4章・6章（サマリの計算式と分子・分母）が当方の実装に直結いたします。**★
★**11章は、Q11-1（実際の清掃開始時刻）について、お伺いする内容を
「どこにありますか」から ★**「この理解で実装してよろしいでしょうか」**★ に改めております。**★

本書は次の12部構成です（★**質問25問 / お願い5件 / 参考情報1章**★）。

| # | 内容 | 種別 | 優先度 |
|---|---|---|---|
| **1. 索引について** | ★**ご対応中と伺いました。当方の `EXPLAIN` 実測と、当方が見ていた列の一覧です**★ | ★参考情報★ | ★—★ |
| **2. サマリの面積は期間内の合計でしょうか** | ★**仕様の確認のみに縮めました**★ | 質問 | ★高★ |
| **3. 第8回 Q4 の残り（サマリの率・分子・分母）** | ★再掲★ | 質問 | 高 |
| **4. サマリの `error_count` の集計範囲** | ★当期と確定期間で定義が食い違う恐れ★ | 質問 | 高 |
| **5. 面積の単位** | ★**弊社で㎡と確定しました。設問は取り下げです**★ | ★ご報告★ | ★—★ |
| **6. グループ単位のサマリ** | ★`group_summaries` が存在しません★ | 質問 | ★高★ |
| **7. グループ・顧客マスタのデータ投入** | ★画面に分類を出すために必要です★ | ★お願い★ | 中 |
| **8. 制御盤の報告間隔** | ★`control_reports` の行数を決めます。台数は当方で把握しました★ | 質問 | 中 |
| **9. 軽い確認2件 + DDL未反映2件** | ★DDLは4回目のお願いです★ | 質問 | 低 |
| **10. DB更新用アカウント** | ★**発行済みでした。ご依頼を取り下げます**★ | ★ご報告★ | ★—★ |
| **11. 清掃の開始時刻とリアルタイム性** | ★**Q11-1 は「実装の確認」に改めました。Q11-4 を新設（4問）**★ | 質問 | 中 |
| **12. DB接続経路についてのお願い3件・確認6問** | ★**実測つき。期限は「ステージングに実データが入る前」です**★ | ★お願い＋質問★ | ★**高**★ |

★**7章は貴社の担当領域（DBとバッチ）への変更を伴いますので、「お願い」として書いております。**★
★**ご負担や副作用のご懸念があれば、その旨をお知らせください。当方で別の手を検討します。**★

---

# 1. ★索引について（★★ご対応中と伺いました。参考情報です★★）★

## 1-0. ★★本章の位置づけ — ご依頼は取り下げております★★

★**索引についてはご対応中と伺いました。つきましては本章は依頼ではなく参考情報です。**★
★**ご対応が完了した時点で、残っているものがあれば改めてご相談します。**★

★**本章に残しておりますのは、当方が `EXPLAIN` で実測した結果と、当方が見ていた列の一覧です。**★
★**貴社が入れられた索引で足りているかどうかを、そちらで突き合わせていただけるように
残しております。**★
★**この一覧のとおりにしていただきたい、という意味ではありません。**★

★**初版（2026-09-15）では本章を「最優先のご依頼（7件）」として書いておりました。
本改訂（2026-09-17）で取り下げております。行き違いがございましたら申し訳ございません。**★

## 1-1. なぜこの列を見ていたか

当方は清掃詳細ログの表示期間を ★**それまでの上限31日から、上限2年（731日）に広げました**★。

そのために `EXPLAIN` で実行計画を確認したところ、★**索引が無いために全表走査になっている
経路が複数見つかりました。**★ 以下の①〜⑦は、そのとき当方が見ていた列です。

★**現状（データが少ないうち）は問題が表に出ません。**★
★**問題になるのは、本番のデータが積み上がってからです。**★

以下の `SHOW CREATE TABLE` と `EXPLAIN` は、★**テスト環境で実際に実行したものです。推測ではありません。**★

★**ただし、そこに出てくる行数（`rows` / `r_rows`）は当方が入れた検証用データの件数です。**★
★**申し上げたいのは `type` / `possible_keys` / `key` という実行計画の形のほうで、行数ではございません。**★
★**詳しくは冒頭の「おことわり」をご覧ください。**★
実測環境: `mysql://…@133.125.238.144:13306/clean_watch` / `VERSION() = 10.11.19-MariaDB-ubu2204`

★**なお `ALTER TABLE` の形で書いておりますのは、列と順序を誤解なくお伝えするためです。**★
★**当方でこれを実行することはございません（当方はメインDBのスキーマを変更しない方針です）。**★

## 1-2. ★★①② — 索引が1本も無い列★★

```sql
ALTER TABLE `clean_status_histories`
  ADD INDEX `clean_status_histories_clean_timetable_id_index` (`clean_timetable_id`);

ALTER TABLE `robot_error_reports`
  ADD INDEX `robot_error_reports_clean_timetable_id_index` (`clean_timetable_id`);
```

### 根拠（`EXPLAIN` の出力そのまま）

> ★★**行数の読み方について**★★
> ★以下の `rows` / `r_rows` は、★**当方が入れた検証用データでの行数**★です（「おことわり」参照）。
> ★**本番の行数を示すものではありません。**★
> ★一方、`type` / `possible_keys` / `key` は ★**表の構造（索引の有無）から決まる**★もので、
> ★**行数によって変わりません。**★ ★**本章で申し上げたいのは後者です。**★

`clean_status_histories` を `clean_timetable_id IN (5件)` で引いたとき:

```
type=ALL | possible_keys=null | key=null | key_len=null
rows=538 | r_rows=538.00 | filtered=100 | r_filtered=0.93 | Extra=Using where
```

`robot_error_reports` を同様に引いたとき:

```
type=ALL | possible_keys=null | key=null
rows=49 | r_rows=49.00 | filtered=100 | r_filtered=4.08 | Extra=Using where
```

★**`possible_keys = null` ＝ 使える索引が1本もありません。**★
★表の全行を読んで、そのうち一致した行だけを残しています★
（★上の 538行・0.93% は ★**当方の検証用データでの値**★です）。

これは統計に基づくコスト判断ではなく、★**構造的な全表走査**★です。行数が増えても
索引を選ぶようにはなりません。

### `SHOW CREATE TABLE` での確認

```
-- clean_status_histories
UNIQUE KEY `clean_status_histories_id_unique`           (`id`)
KEY        `clean_status_histories_facility_id_foreign` (`facility_id`)
KEY        `clean_status_histories_section_id_foreign`  (`section_id`)
-- ★clean_timetable_id には索引も FK もありません★

-- robot_error_reports
UNIQUE KEY `robot_error_reports_report_id_unique`    (`error_id`)
KEY        `robot_error_reports_facility_id_foreign` (`facility_id`)
KEY        `robot_error_reports_section_id_foreign`  (`section_id`)
KEY        `robot_error_reports_robot_id_foreign`    (`robot_id`)
-- ★clean_timetable_id には索引がありません★
```

### 影響の大きさ（★★2026-09-17 に前提を置き直しました★★）

当方のアプリは、この2つのテーブルを ★**`clean_timetable_id IN (…)` の形でしか引きません。**★
`IN` の要素数が1000を超えると1000件ずつの塊に分けて投げますが、★**塊ごとに全表走査が起きます。**★

★**初版ではこの走査行数を「施設200件」という当方の仮置きで外挿しておりました。**★
★**その後、弊社で現状のロボット台数を確認したところ ★★30台未満★★ でしたので、
置き直しております。**★

★**台数の根拠は、弊社（DFA）自身の把握「現状30台未満」（2026-09-17）です。**★
★**貴社への質問ではございません。**★

#### 計算過程

> ★★**下の「1台1日2回」は、貴社のデータから得た値ではありません。**★★
> ★当方が入れた検証用データの密度（31日 / 12エリア / 538行 ＝ 1.45 回/日/エリア）を
> 切り上げた、★**当方の置き値**★です。★
> ★**実運用の清掃回数が決まりましたら、当方から置き直してお知らせいたします。**★

```
1) 1ロボット（＝1清掃エリア）あたりの1日の清掃予定回数
   ★当方の置き値★（当方の検証用データの密度 1.45 回/日/エリア を切り上げたもの）
   → ★2 回/日/台★ として計算する

2) 2年ぶんの行数（当方の画面の期間上限は 731日です）
   30台 × 2回/日 × 731日 = ★43,860行★
   ＝ clean_timetables（precheck = 0）の行数。
     clean_status_histories も同数とみなす
     （★当方の検証用データでは 1対1 でしたが、本来の仕様は 2章 Q2-3 でお伺いしております★）

3) IN の塊の数
   43,860 ÷ 1,000 → ★44塊★

4) 走査行数（1塊につき全表走査1回）
   44塊 × 43,860行 = ★約 193万行★
```

| 表示期間 | 塊の数 | 走査行数（`clean_status_histories`・★ロボット30台で外挿★） |
|---|---|---|
| 今日1日 | 1 | 約 4.4万行 |
| ★2年（731日）★ | ★44★ | ★**約 193万行**★ |

★**初版（施設200件での外挿）では「2年で約6,430万行」としておりました。約 1/33 になります。**★

### ★★数字が小さくなったことについて、事実だけ申し添えます★★

★**「だから問題ない」と断定するつもりはございません。**★ 分かっていることは次の3点です。

- ★`possible_keys = null` である以上、★**全表走査は行数によらず構造的に起きます**★。
  ★**行数が増えても索引を選ぶようにはなりません**★（統計に基づくコスト判断ではないためです）
- ★清掃詳細ログは、この全表走査を ★**2つの経路（本体と連続日数の算出）で別々に撃ちます**★。
  ★2年の表示1回あたり、合計で 約386万行の走査になります★
- ★上の 43,860行 は「1台1日2回」への切り上げです。★**塊の数と1塊あたりの行数が両方とも
  台数・回数に比例するため、走査行数はそれらに対して二乗で効きます**★。
  ★台数が倍になれば走査行数は4倍になります★

## 1-3. ★③④ — 複合索引（`clean_timetables`）★

```sql
ALTER TABLE `clean_timetables`
  ADD INDEX `clean_timetables_precheck_start_at_index` (`precheck`, `start_at`);

ALTER TABLE `clean_timetables`
  ADD INDEX `clean_timetables_facility_id_start_at_index` (`facility_id`, `start_at`);
```

### 根拠

当方の主クエリは ★**常に `precheck = 0 AND start_at >= ? AND start_at < ?` の AND**★ です。
`start_at` 単独の索引はありますが、実行計画では使われていません。

```
-- 2年範囲の主クエリ
type=ALL | possible_keys=clean_timetables_start_at_index | key=null | key_len=null
rows=1044 | r_rows=538.00 | Extra=Using where; Using filesort
```

施設で絞った場合も同様です。

```
-- 2年範囲 + facility_id IN (1,2,3)
type=ALL | possible_keys=clean_timetables_facility_id_foreign,clean_timetables_start_at_index
key=null | rows=1044 | r_rows=175.00 | filtered=32.47 | Extra=Using where; Using filesort
```

★**単一列の索引が2本とも候補に挙がりながら、どちらも使われていません。**★
これが複合索引を必要とする形そのものです。

> ★★**ただし、ここは①②とは性質が異なります。**★★
> ★③④は `possible_keys` に索引が挙がっておりますので、★**使うかどうかはコスト判断**★です。
> ★**上の実行計画は当方の検証用データ（少量）で測ったものですので、行数が増えれば
> 選択が変わる可能性があります。**★
> ★そのため③④は、①②ほど強くは申し上げられません。★

### ★2本を1本にまとめない理由★

`(facility_id, precheck, start_at)` の1本に寄せる案もありえますが、
★**施設で絞らない呼び出し（画面の既定）が主経路**★であり、その1本では
`precheck = 0 AND start_at` が引けません。★**そのため当方は2本別々のものとして見ておりました。**★

なお `clean_timetables` の既存索引は6本すべて単一列で、★2026-09-13 時点では複合索引は
1本もありませんでした★。

## 1-4. ★⑤ — 期間での集計（面積の累計表示に関係します）★

```sql
ALTER TABLE `clean_status_histories`
  ADD INDEX `clean_status_histories_started_at_index` (`started_at`);
```

### 根拠

当方は ★**清掃総面積を期間で絞って集計する画面**★ を追加しております（本書2章と関連）。
その集計は `clean_status_histories` を期間で絞って `SUM()` を取る形になりますが、
★`started_at` に索引が無いため、期間で絞っても全行を走査します。★

```
EXPLAIN SELECT facility_id, SUM(clean_area) FROM clean_status_histories
 WHERE started_at >= '2026-09-01' AND started_at < '2026-09-14' GROUP BY facility_id;
→ type=index | key=clean_status_histories_facility_id_foreign | rows=538 | Extra=Using where
```

（★`rows` は当方の検証用データでの行数です。★★申し上げたいのは「`started_at` に索引が無い」
という構造のほう★★で、こちらは `SHOW CREATE TABLE` で確認しております）

★**ここでも規模の前提を置き直しております。**★
当方の社内資料は ★「1日約360行・年間約13万行・保持2年」★ を想定しておりましたが、
★これは施設200件規模に相当する数字★でした。

```
ロボット30台 × 2回/日 × 365日 = ★約 2.2万行/年★（2年で 約4.4万行）
```

★**規模は当初想定の 1/6 ほどになりますが、「期間で絞っても全行を読む」という形そのものは
行数によらず変わりません。**★

## 1-5. ★⑥⑦ — D-Security 制御盤（第8回以降に判明）★

```sql
ALTER TABLE `control_reports`
  ADD INDEX `control_reports_control_id_reported_at_index` (`control_id`, `reported_at`);

ALTER TABLE `control_error_histories`
  ADD INDEX `control_error_histories_occurred_at_index` (`occurred_at`);
```

### ⑥の根拠 — ★★同じテーブル・同じ索引で、列を変えただけで実行計画が切り替わりました★★

制御盤ごとの「最終通信時刻」を取るため `MAX(reported_at)` を使っています。

| `MAX()` の対象 | 索引に含まれるか | `type` | `rows` | `Extra` |
|---|---|---|---|---|
| `reported_at`（現行） | ★含まれない★ | `index`（★フルスキャン★） | 14 | `Using where` |
| `id`（参考の実験） | ★含まれる★ | ★`range`★ | ★3★ | ★`Using index for group-by`★ |

（★`rows` は当方の検証用データでの行数です。★★ご覧いただきたいのは `type` と `Extra` が
切り替わった点★★です）

★InnoDB の二次索引には主キーが暗黙に付く★ため、既存の `control_reports_control_id_foreign` は
物理的に `(control_id, id)` の複合索引として働いています。★**2列目が `reported_at` になれば、
`MAX(reported_at)` にも同じ効果が及びます。**★

★`control_reports` は心拍の報告が積み上がるテーブルで、本番では最も行数が多くなる見込みです★
（★8章の報告間隔次第で1,100万行〜7,000万行。★**制御盤11台という当方の置き値での試算です**★★）。
★**ここが全表走査のままですと、D-Sログ画面が開けなくなります。**★

★**清掃側（①〜⑤）とは事情が異なります。**★ ★清掃側の行数は台数と清掃回数で決まりますが、
`control_reports` は ★**時間あたりの報告間隔で決まる**★ため、台数が少なくても行数は積み上がります。
★**そのため上の「ロボット30台」の置き直しは、⑥⑦には効きません。**★

### ⑦の根拠

D-Secアラートの絞り込みで `occurred_at` の範囲指定を使いますが、索引がありません。

## 1-6. ★①〜⑦の一覧（突き合わせ用）★

★**貴社のご対応内容と突き合わせていただくための一覧です。**★

| # | テーブル | 当方が見ていた列（順序も含みます） | 2026-09-13 時点の実測 |
|---|---|---|---|
| ① | `clean_status_histories` | `clean_timetable_id` | ★索引なし（`possible_keys = null`）★ |
| ② | `robot_error_reports` | `clean_timetable_id` | ★索引なし（`possible_keys = null`）★ |
| ③ | `clean_timetables` | `(precheck, start_at)` | 単一列索引はあるが実行計画で未使用 |
| ④ | `clean_timetables` | `(facility_id, start_at)` | 同上 |
| ⑤ | `clean_status_histories` | `started_at` | ★索引なし★ |
| ⑥ | `control_reports` | `(control_id, reported_at)` | `(control_id)` のみ。`MAX(reported_at)` がフルスキャン |
| ⑦ | `control_error_histories` | `occurred_at` | ★索引なし★ |

★**申し添え**★

- ★①〜⑦のテーブルは、いずれも ★**貴社のデータ収集処理が書き込むテーブル**★です。★
  ★**索引を足すぶん、書き込みがわずかに遅くなります。**★
  ★**その兼ね合いのご判断は貴社にお任せいたします。**★
- ★**当方の見立てでは ①② が突出しています**★（索引が1本も無い列のため）。
  ★**③〜⑦は、①②の後で差し支えありません。**★
- ★当方はメインDBのスキーマを変更しない方針です。★
  ★**上記を当方で実行することはございません。**★
- ★**ご対応が完了しましたら、その旨をお知らせいただけますと、当方で `EXPLAIN` を測り直し、
  残りがあるかどうかを確認いたします。**★

---

# 2. ★★サマリの面積は、期間内の合計でしょうか（仕様の確認）★★

## 2-1. ★★本章は仕様の確認のみに縮めております★★

★**初版では、テスト環境の `facility_summaries` / `customer_summaries` の値を並べて
「合計に見えません」と申し上げておりました。**★
★★**この値は当方が入れた検証用のダミーデータでしたので、当該の指摘は取り下げます。**★★
★**お騒がせいたしました。**★

★**残しますのは、実装のために必要な仕様の確認だけです。**★
★当方は ★**「清掃総面積の累計」を画面に表示する機能**★ を作っており、
★その数字をサマリから取るのか、`clean_status_histories` から毎回その場集計するのかを
決める必要があります★（後者を選ぶ場合に効くのが、1章の⑤の列です）。

## 2-2. お伺いしたいこと（2問）

### ★Q2-1. 集計バッチは、`task_area` / `clean_area` に ★**期間内の合計**★ を書き込む仕様でしょうか★

| 選択肢 | 内容 |
|---|---|
| ★A★ | ★**期間内の合計を書く**★（当方はサマリをそのまま足し合わせて総面積を出します） |
| B | ★**合計ではない**★（1回ぶんの代表値・平均など。その場合、定義をお教えください） |

★**B の場合、当方は `clean_status_histories` から毎回その場集計する形にいたします。**★
★**「サマリに合計を入れるほうが筋がよい」というご判断であれば、そちらに合わせます。**★

### ★Q2-3. 1つの `clean_timetable_id` に対し、`clean_status_histories` は何行できますでしょうか★

★**面積の合計をSQLの `SUM()` で取るか、行を1本に畳んでから足すかが、これで変わります。**★

| 選択肢 | 内容 |
|---|---|
| ★A★ | ★**必ず1行**★（清掃1回につき1行） |
| B | ★**複数行できる**★（清掃前 → 清掃中 → 清掃終了 のように状態ごとに積む） |

★**「清掃状態履歴」というテーブル名からは、B の設計ではないかとも思われます。**★
★**一方で `clean_status_histories` にはカラムとしての状態（`clean_status_trans` 相当）が
無く、この点は A のようにも読めます。**★
★**どちらとも決めかねましたので、お教えください。**★

★**B の場合、`SUM()` で足すと同じ清掃の面積を何度も数えてしまいます。**★
★**そして、それは例外もエラーも出さずに、ただ数字が大きくなるだけです。**★

★**当方は安全側（B の前提で、最新の1行に畳んでから足す）で実装いたしますが、
A と確定できるのであれば、そのほうが速くなります。**★

> ★**設問番号について**★: ★初版の Q2-2（「合計でない場合の正しい経路をお教えください」）は
> 取り下げました★（Q2-1 の B に当方の対応を書きましたので、独立の設問にする必要が
> なくなったためです）。★**番号は詰めずに `Q2-3` のままにしております。**★

## 2-4. ★参考: 年次サマリの桁あふれについて（優先度は低いです）★

★**ご依頼でも質問でもなく、気づいた点のご報告です。**★

```
facility_summaries.task_area / clean_area   double(14,6)  → 上限 約 1億㎡
customer_summaries.task_area / clean_area   double(14,6)  → 同上
```

★**もしサマリに期間内の合計を入れる場合（Q2-1 が A の場合）、年次の行が上限に当たる可能性があります。**★

| 前提 | 上限に達する条件 |
|---|---|
| ★ロボット30台・年365日★ | ★1台1日あたり 約9,100㎡ を超えると、年次行があふれます★ |

```
1億㎡ ÷ 30台 ÷ 365日 ≒ 9,132 ㎡/台/日
```

★**これは当方の計算であり、実測ではありません**★
（★当方の手元には実際の店舗面積の値がございませんので、9,100㎡ が現実的な値かどうかは
判断できておりません★）。

★**初版では「施設200件」を前提に 約1,370㎡ としておりましたが、弊社で現状のロボット台数を
確認したところ30台未満でしたので、置き直しております（1章と同じ前提です）。**★
★**桁あふれの可能性はそのぶん遠のきました。**★

★**週次・月次では問題になりません。P1 で当方が読むのも週次・月次のみです。**★
★**年次サマリを作られる際にご一考いただければ、という程度のものです。**★

---

# 3. ★第8回 Q4 の残り（サマリの率・分子・分母の関係）— 再掲★

第8回で「多いので後で回答」との留保をいただいた件です。★**取り下げておりません。**★

お伺いしたい内容は第8回の4章と同じです。要点だけ再掲します。

- サマリに入る各率（`clean_ratio` 等）の ★**計算式**★
- ★**分子・分母に対応するカラム名**★
- 件数列（`task_count` 等）が ★**何を数えているか**★（予定の数か、実施の数か）

★**2章の面積の件と同じ枠の話ですので、あわせてご回答いただけますと助かります。**★

---

# 4. ★サマリの `error_count` の集計範囲★

第8回 A7 でいただいたご回答が、★**「バッチが実際にそうしている」のか「当方への助言」なのか**★
を読み取れませんでした。★**当期（進行中の週・月）は当方が自前で集計するため、
定義が食い違うと、確定期間と当期でグラフが段差になります。**★

## お伺いしたいこと（3問）

### ★Q4-1. サマリの `error_count` は、事前チェック（`precheck = 30 / 60`）を除外して集計されていますでしょうか★

| 選択肢 | 内容 |
|---|---|
| A | ★除外している★（本清掃 `precheck = 0` のみを数えている） |
| B | ★除外していない★（事前チェックのエラーも数えている） |

### ★Q4-2. `clean_timetable_id` が `null` のエラー行は、サマリの `error_count` に含まれますでしょうか★

### ★Q4-3. `clean_error` が 2（セキュリティ有効）/ 3（D-S制御盤異常）の清掃は、サマリの `error_count` に含まれますでしょうか★

★第8回 A6-1 で「2 / 3 では `robot_error_reports` が作られない」とのご回答をいただいております。★
★**その場合、サマリ側でも数えていない、という理解でよろしいでしょうか。**★

---

# 5. ★面積の単位（★★設問を取り下げます★★）★

★**初版では「`task_area` / `clean_area` の単位は平方メートル（㎡）でしょうか」と
お伺いしておりました（Q5-1）。**★

★★**本件は弊社（DFA）で「㎡」と確定いたしましたので、設問を取り下げます。**★★
★**画面には ㎡ として表示いたします。**★

★**貴社にご対応いただくことはございません。**★
★**万一「㎡ではない」という事情がございましたら、その場合のみお知らせください。**★

---

# 6. ★グループ単位のサマリ★

## 6-1. `group_summaries` に相当するテーブルが見当たりません

サマリ系のテーブルは次の4本と認識しております。

```
customer_summaries        / customer_error_summaries   （customer_id を参照）
facility_summaries        / facility_error_summaries   （facility_id を参照）
```

★**グループ（`groups`）単位のサマリがありません。**★

当方は ★**ホールディングス単位のKPIを画面に出す**★ 予定です（本書7章と関連）。

## お伺いしたいこと（1問）

### ★Q6-1. グループ単位の集計は、どちらの想定でしょうか★

| 選択肢 | 内容 |
|---|---|
| ★A★ | ★**当方が `customer_summaries` の複数行を合算する**★（テーブル追加は不要） |
| B | ★**`group_summaries` を追加してバッチで集計する**★ |
| C | ★グループ単位の集計は想定していない★ |

★**A の場合、率は「率の平均」ではなく「Σ分子 ÷ Σ分母」で再計算いたします。**★
★**分子・分母がサマリに入っている前提ですので、3章のご回答と関係します。**★

## 6-2. ★★ところが、4つの率のうち2つは分子・分母が揃っておりません★★

★**本節は、テーブルのカラム構成（DDL）と当方の計算式を突き合わせたもので、
行の中身には依存しておりません。**★

サマリのカラムを当方の計算式（要件定義）と突き合わせたところ、次のようになりました。

| 率 | 計算式（当方の定義） | サマリの分子 | サマリの分母 | 合算できるか |
|---|---|---|---|---|
| 清掃完了率 `clean_ratio` | Σ清掃面積 ÷ Σ対象面積 | `clean_area` | `task_area` | ★**できる**★ |
| 出発成功率 `launch_ratio` | 定刻出発回数 ÷ 予定回数 | `launch_count` | `task_count` ? | ★式が未確認★ |
| ★稼働率 `operation_ratio`★ | 清掃★**実施**★回数 ÷ 予定回数 | ★**該当カラムが無い**★ | `task_count` ? | ★★**できない**★★ |
| ★エラー発生率 `error_ratio`★ | エラー発生回数 ÷ 清掃★**実施**★回数 | `error_count` | ★**該当カラムが無い**★ | ★★**できない**★★ |

★**「清掃実施回数」に当たるカラムが見当たりませんでした。**★

### ★★なぜ「清掃実施回数」が要るのか（Q6-2 の理由）★★

★**当方の4つの率のうち、2つは「清掃実施回数」を必要とします。**★

```
稼働率       = 清掃★実施★回数 ÷ 清掃★予定★回数 × 100
エラー発生率 = エラー発生回数 ÷ 清掃★実施★回数 × 100
```

★**つまり「実施回数」は、一方の率では分母、もう一方の率でも分母に当たります。**★

★**そして `task_count` は、予定回数か実施回数かのどちらか一方にしかなりません。**★

| `task_count` が何であれば | 困ること |
|---|---|
| ★**予定回数**★（当方の理解） | ★**実施回数が無い**★ → ★稼働率の分子・エラー発生率の分母が出せません★ |
| ★実施回数★ | ★**予定回数が無い**★ → ★稼働率の分母が出せません★ |

★**いずれにせよ、現在のカラム構成では2つの率のうち少なくとも片方が計算できません。**★
★（`task_count` が実際にどちらなのかは、3章でお伺いしております）★

★**これは合算のときだけの話ではありません。**★
★★**確定した期間（前週・前月）の稼働率・エラー発生率そのものが、サマリからは出せません。**★★
★**進行中の期間は当方が詳細テーブルからその場集計しますので出せますが、確定期間は
サマリを読む設計ですので、そこで数字が欠けます。**★

★**複数顧客を合算する場合は、さらに事情が重くなります。**★
★**率の平均を取るのは誤りで、分子と分母をそれぞれ足してから割る必要がありますが、
この2つはその材料がありません。**★

### ★Q6-2. サマリに「清掃実施回数」のカラムを追加していただくことは可能でしょうか★

| 選択肢 | 内容 |
|---|---|
| ★A★ | ★**追加できる**★（`customer_summaries` / `facility_summaries` に1カラムずつ） |
| B | ★**すでに既存のカラムで表現されている**★（どれか教えてください） |
| C | ★追加は難しい★ |

★**C の場合、当方は確定期間（前週・前月）の稼働率・エラー発生率を画面に出さず、
清掃完了率と総清掃面積だけを出す形にいたします。**★
★**進行中の期間だけ2つの率が出て、確定期間では消える、という見え方になります。**★

★**初版では「効いてくるのは2社目から」と書いておりましたが、これは合算の話に限った
見立てでした。**★
★**上のとおり、1社であっても確定期間の2つの率が出せませんので、訂正いたします。**★
★**お急ぎいただく必要はございませんが、設計を決めたいので方針だけ伺えますと助かります。**★

---

# 7. ★グループ・顧客マスタのデータ投入のお願い★

## 7-1. 背景

当方は画面に ★**「ホールディングス → グループ（ブランド）→ 店舗」の3階層の絞り込み**★ を
出す予定です。

テーブルの構造（`groups` → `customers.group_id` → `facilities.customer_id`）は
★**すでに3階層になっており、当方から追加をお願いする必要はございません。**★

★**ただし、当方の手元には本番の中身がございません。**★

★テスト環境に入っておりますのは ★**当方が入れた検証用のダミー**★（`groups` 1行 /
`customers` 1行 / `facilities` 12行・全行が同じ `customer_id`）だけです。★
★**そのため当方では、3階層の絞り込みが実データでどう見えるかを確かめられておりません。**★

## 7-2. お願いと、確認したいこと

### ★お願い: 本番の `groups` / `customers` のデータ投入をお願いいたします★

★**時期の目安だけでも結構です。**★
★**当方はそれまで、検証用の複数グループ・複数顧客のデータを自前で用意して進めます。**★

### ★Q7-1. `customers` は、法人と屋号のどちらの粒度で入る想定でしょうか★

★**当方は「屋号（ブランド）」の粒度で画面を作る方針です。**★

| 選択肢 | 例 |
|---|---|
| ★A★ | ★**屋号**★（ドン・キホーテ / MEGAドン・キホーテ / アピタ / ピアゴ …） |
| B | ★法人★（株式会社ドン・キホーテ / 株式会社ユニー） |

★**A と B では、同じ法人の中で屋号を分けられるかどうかが変わります。**★
★**貴社の収集処理がどちらの粒度で `customers` を作る想定かをお教えください。**★

### ★Q7-2. 屋号を持たない顧客は、どう表現されますでしょうか★

★当方は「屋号が無い顧客もありうる」という前提で画面を作ります。★
`customers.group_id` は ★0 がセンチネル（グループなし）★ と認識しておりますが、
★**屋号そのものが無い場合に `customer_name` に何が入るか**★をお教えください。

### ★Q7-3. `facilities.shop_id`（`varchar(20)`、既定 `'0'`）は何を表す列でしょうか★

★テーブル定義書からは読み取れず、★**テスト環境の値も当方が入れたダミー（全行 `"0"`）でしたので、
値から推し量ることもできませんでした。**★★
★**顧客側の店舗コードでしょうか。分類の手がかりに使えるかを知りたく存じます。**★

> ★**設問の並びについて**★
>
> ★本節は **Q7-5 → Q7-4** の順に並んでおります★。Q7-4（`group_id = 0` が投入できない件）が
> Q7-5 のご回答を前提とする内容のため、この順にしております。
> ★**当方の管理表がこの番号で追っておりますので、番号は振り直しておりません。**★

### ★★Q7-5. 「屋号を持たない顧客」は、3階層のどの段が空くという意味でしょうか★★

★**当方の中でも解釈が割れましたので、貴社のDBの想定を伺わせてください。**★

当方が作ろうとしている階層はこの3段です。

```
ホールディングス  →  屋号（ブランド）  →  店舗
   groups              customers          facilities
```

「屋号を持たない顧客がありうる」と伺っておりますが、★**どの段が空くのかで設計が変わります。**★

| 解釈 | 空くのは | 例 | DBでの表現 |
|---|---|---|---|
| ★①★ | ★真ん中（屋号）★ | 店舗がホールディングスの直下にぶら下がる | ★**表現できません**★ — `facilities.customer_id` は NOT NULL で `customers` を指すため、中間を飛ばせません |
| ★②★ | ★上（ホールディングス）★ | 屋号はあるが、属する持株会社が無い | `customers.group_id = 0`（＝ Q7-4 の件） |

★**② であれば、Q7-4 が解決すればそのまま作れます。**★

★**① の場合、`customers` にダミーの行を1件作って、そこに店舗をぶら下げることになります。**★
★**その場合、`customer_name` に何を入れるか（空文字は避けたく存じます）をお決めいただく必要があります。**★

★**貴社の収集処理が `customers` をどう作る想定かをお教えいただければ、当方はそれに合わせます。**★

### ★★Q7-4. `customers.group_id = 0`（グループなし）は、現状のDDLでは投入できないように見えます★★

★**これは質問というより、実DDLの矛盾のご報告です。**★

当方は `customers.group_id` について、★**「NOT NULL / 既定値 0 / 0 はグループなしを表すセンチネル」**★
と理解しております（貴社より、索引の効率を理由にこの方式を採る旨のご回答をいただいております）。

★**ところが、実際のDDLでは 0 を投入できません。**★ 当方が接続して確認した内容です。

```sql
-- SHOW CREATE TABLE customers （抜粋）
`group_id` bigint(20) unsigned NOT NULL DEFAULT 0,
CONSTRAINT `customers_group_id_foreign` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`)
```

```
SELECT @@foreign_key_checks;           →  1（★外部キー制約は有効です★）
SELECT @@sql_mode;                     →  NO_AUTO_VALUE_ON_ZERO は含まれておりません
```

★**外部キー制約が有効である以上、`group_id = 0` の顧客を INSERT するには、
`groups` に `id = 0` の行が存在していなければなりません。**★
★**`group_id` を省略して INSERT した場合も、既定値の 0 が入るため同じです。**★

★そして `groups.id` は `AUTO_INCREMENT` ですので、★**`id = 0` の行を入れること自体に
`NO_AUTO_VALUE_ON_ZERO` が必要**★ですが、上のとおり `sql_mode` には含まれておりません。★

> ★**申し添え**★: ★テスト環境の `groups` には `id = 0` の行がございませんでしたが、
> ★**この表の中身は当方が入れた検証用のダミー**★ですので、貴社の想定を示すものでは
> ありません。★
> ★**そのため本件は「実データがこうなっている」ではなく、「DDLと `sql_mode` の
> 組み合わせ上こうなる」というご報告です。**★

## ★Q7-4 でお伺いしたいこと★

★**当方はメインDBのスキーマを変更しない方針のため、当方では直せません。**★
★**どの形がよいか、貴社のご判断をお聞かせください。**★

| 選択肢 | 内容 | 備考 |
|---|---|---|
| ★A★ | ★`groups` に `id = 0` の番人行を1件入れる★ | ★INSERT には `NO_AUTO_VALUE_ON_ZERO` が必要になります★ |
| B | ★外部キー制約 `customers_group_id_foreign` を外す★ | センチネル方式と両立します |
| C | ★`group_id` を nullable にする★ | ★索引効率を理由にセンチネル方式を採られた経緯があるため、蒸し返しになります★ |
| D | ★グループなしの顧客は存在しない★（必ずどこかのグループに属する） | ★この場合、当方は「グループなし」の表示を作りません★ |

★**D であれば、対応は不要です。その旨だけお知らせください。**★

---

# 8. ★制御盤の報告間隔★

## 8-1. ★★台数については、当方で把握いたしました（設問を取り下げます）★★

★初版では「P1 稼働時点の施設数」「ロボット・D-S制御盤の台数」の2問を貴社にお伺いしておりました。★
★**この2問は取り下げます。**★

★**理由: 本番の規模は弊社（DFA）側で決めるべきことであり、貴社にお伺いする筋のものでは
ありませんでした。当方の記録にもその旨が残っておりました。**★

★**現時点の当方の把握は次のとおりです。参考までにお知らせいたします。**★

| 項目 | 当方の把握 | 出典 |
|---|---|---|
| ★ロボット台数★ | ★**現状 30台未満**★ | ★弊社（DFA）の把握。2026-09-17★ |
| D-S制御盤の台数 | ★未確定★（試算では ★11台★ と置いております） | ★弊社で確定させます★ |
| 施設数 | ★未確定★ | ★弊社で確定させます★ |

★**上の「11台」は、当方がテスト環境に入れた検証用データの台数をそのまま置き値に
したものです。**★★実運用の台数ではありません。★

★**1章・2-4 の外挿は、この「ロボット30台」を前提に置き直しております。**★
★**台数が大きく動いた場合は、当方から改めてお知らせいたします。**★

## お伺いしたいこと（1問）

### ★Q8-3. `link_schedules.intervals`（制御盤の報告間隔・秒）は、運用上どの範囲で動きますでしょうか★

★**初版では「実運用値をお教えください」と、固定の1つの値を伺う形で書いておりました。**★
★**その後、この値は運用上変わりうるものだと分かりましたので、聞き方を改めます。**★

★**お教えいただきたいのは、次の3点です。**★

| # | 伺いたいこと | 例 |
|---|---|---|
| ★a★ | ★**運用上の下限（最短の報告間隔）**★ | 「10秒より短くはしない」など |
| ★b★ | ★**運用上の上限（最長の報告間隔）**★ | 「長くても60秒」など |
| ★c★ | ★**変更の頻度**★ | 「初期設定から基本的に変えない」／「制御盤ごとに個別に決める」／「運用中に随時変える」など |

★**おおよそで構いません。**★★**「だいたいこの範囲」が分かれば十分です。**★

### ★なぜ範囲と頻度を伺うのか★

★**ここが `control_reports` の行数を決めるためです。**★
★**そして、行数の見積もりが6倍変わります。**★

| 報告間隔 | 2年間の行数（★制御盤11台と置いた試算★） |
|---|---|
| 60秒（定義書の例） | 約 1,100万行 |
| ★10秒★（第2回のご回答の例） | ★**約 7,000万行**★ |

★**1,100万行と7,000万行とでは、索引の要否（1-5 の⑥）も、画面の作り方も変わります。**★
★**下限が分かれば「最大でどこまで積み上がるか」を押さえられますし、変更の頻度が分かれば、
その前提がいつまで持つかを判断できます。**★

★**なお、上の台数（ロボット30台未満）はこの試算には効きません。**★
★`control_reports` の行数は台数よりも報告間隔で決まるためです（1-5 ⑥に同じことを書いております）。★

> ★**設問番号について**★: 本章の設問は `Q8-3` のみとなりますが、★番号は詰めずに `Q8-3` のまま
> にしております★（当方側の管理表がこの番号で対応を追っているためです。ご了承ください）。

---

# 9. ★軽い確認2件 + DDL未反映2件★

## ★Q9-1. 第8回 A9-2 の `robot_task_reports` は、DDL 上の `clean_task_reports` のことでしょうか★

★テーブル一覧に `robot_task_reports` が見当たりませんでした。★
★**なお、仮にそうであっても当方の実装は `clean_status_histories` を読んでおりますので、
影響はございません。表記の確認のみです。**★

★**あわせて、`clean_task_reports` に ★★今後データが入る予定があるか★★ もお教えいただけますと
助かります。**★
★テスト環境のこの表には行がございませんが、★**そこに入っているデータは当方が用意した
検証用のものですので、貴社の収集処理が書くかどうかは当方では分かりません**★。★

## ★Q9-2. 1回の清掃の中の、区域別の内訳は取得できますでしょうか★（聞き直し）

★第8回でもお伺いした件です。★
当方が実装できたのは ★**「1清掃エリア（＝1ロボット）につき1つの完了率」**★ までで、
★売り場・通路・レジ前といった内訳★ではありません。

★**取得できない場合は「できない」とお答えいただければ、当方はこの機能を諦めます。**★

## ★お願い: DDL 未反映の2件（★4回目★）★

★**急ぎません。お手すきの折で結構です。**★

| # | 内容 |
|---|---|
| 1 | `clean_status_histories.id` の `AUTO_INCREMENT` |
| 2 | `security_status_histories.reported_at` の `DEFAULT` |

---

# 10. ★DB更新用アカウント（★★すでに発行済みでした。ご依頼を取り下げます★★）★

★**第5回（2026-09-07）・第6回（2026-09-08）・第8回（2026-09-11）から継続してお願いして
おりました件です。**★

★★**当方が接続して確認いたしましたところ、必要な `UPDATE` 権限はすでに付与されておりました。**★★

```
SHOW GRANTS FOR CURRENT_USER();   （2026-09-17 に当方が実行）
→ GRANT UPDATE ON `clean_watch`.`robot_error_reports` …
→ GRANT UPDATE ON `clean_watch`.`control_error_histories` …
```

★**当方が必要としていたのは、この2つのテーブルの
`status` / `comment` / `responded_at` / `resolved_at` の更新のみです。**★
★**すでに満たされております。**★

★★**ご対応済みであることに気づかず、3回にわたって重ねてお願いしてしまいました。
当方の確認漏れです。失礼いたしました。**★★

★**本件は取り下げます。貴社にご対応いただくことはございません。**★

---

# 11. ★清掃の開始時刻と、リアルタイム性について★

## 11-1. ★★Q11-1 は、お伺いする内容を改めました★★

★**初版では「ロボットが実際に清掃を開始した時刻は、どのテーブル・どのカラムに
入りますでしょうか」とお伺いしておりました（Q11-1）。**★

★**そのように申し上げた根拠は2つございましたが、いずれも当方側の事情でした。**★

1. ★テーブル定義書の `started_at` の備考が「清掃スケジュールの清掃開始日時を格納する」と
   読め、★**予定時刻の写しのように見えた**★こと
2. ★テスト環境で予定時刻との差を取ったところ全件0分だったこと★ —
   ★★**ただしこのデータは当方が入れた検証用のダミーで、予定時刻をそのまま
   `started_at` にも入れていたものでした**★★

★★**弊社内で確認いたしましたところ、`clean_status_histories.started_at` を
実際の清掃開始時刻として扱ってよい、との結論になりました。**★★
★**誤った前提でお手を煩わせるところでした。失礼いたしました。**★

★**つきましては、お伺いする内容を「どこにありますか」から「この理解で実装してしまって
よろしいでしょうか」に改めさせていただきます。**★

### ★★Q11-1. `clean_status_histories.started_at` を実際の清掃開始時刻として実装を進めますが、問題ございませんでしょうか★★

★**当方が書こうとしている実装は次のとおりです。**★

```
実開始時刻  = clean_status_histories.started_at
遅延        = started_at − clean_timetables.start_at
出発失敗    = 予定開始時刻 + 猶予30分 を過ぎても started_at が入らない
```

★**確認させていただきたい理由**★ — ★テーブル定義書の `clean_status_histories.started_at` の
備考が ★**「清掃スケジュールの清掃開始日時を格納する」**★ と書かれており、
★**予定時刻の写しとも読めてしまう**★ためです。

★★**もし実際には予定時刻が入る列でしたら、上の「出発失敗」は永久に0件になります。**★★
★**エラーにもならず、画面上は「全件が時間どおりに出発した」と表示され続けます。**★
★**そのため、実装前に一言だけ確認させていただきたい次第です。**★

| ご回答 | 当方の動き |
|---|---|
| ★A. その理解で問題ない★ | ★このまま実装します★（★ご回答はこの一言で結構です★） |
| ★B. `started_at` には予定時刻が入る★ | ★実装を止め、実開始時刻の所在を改めてご相談します★ |

★**貴社の収集処理の都合で「いまは予定時刻を書いているが、今後は実開始時刻を書く」といった
事情がございましたら、その旨もお教えいただけますと助かります。**★

## 11-2. ★背景（残る3問の前提）★

当方は、清掃が ★**「予定時刻から遅れて始まった／始まらなかった」**★ という状態を
画面に出そうとしております。

当方の要件定義では、清掃失敗を次のように定めております。

> 予定開始時刻 + ★**猶予30分**★ を経過してもタスク開始が確認できない

★`started_at` で遅延そのものは出せるようになりましたが、★**次の2点は `started_at` だけでは
埋まりません**★。★

- ★`started_at` が入らなかったとき、★**「指示すら出ていない」のか「指示は出たが動き出さなかった」
  のか**★ が区別できません（→ Q11-2）
- ★貴社のサマリに入っている「出発成功」と、当方の日次判定とで ★**定義がそろっているか**★ が
  分かりません（→ Q11-3）

## お伺いしたいこと（★Q11-1 のほかに3問★）

### ★Q11-2. `clean_statuses.clean_status_trans` が 1（清掃指示）で止まったケースは、履歴として残りますでしょうか★

定義書によれば `clean_status_trans` は
`0: 清掃開始前, 1: 清掃指示, 2: 清掃中, …` と推移します。

★**「1（清掃指示）で止まった ＝ 指示は出したが動き出さなかった」と読めますので、
これが取れれば出発失敗を判定できます。**★

★**ただし `clean_status_histories` にこのカラムが無く、`clean_statuses`（現在の状態）は
清掃ごとに上書きされるため、過去を遡ることができません。**★

★**履歴に残る仕組みがあるかをお教えください。**★

### ★Q11-3. `facility_summaries.launch_count` / `launch_ratio`（出発成功数・出発成功率）の計算式をお教えください★

★**サマリには、貴社が計算済みの「出発成功数・出発成功率」のカラムが実在しております。**★
★**つまり貴社側では「出発に成功したか」を判定できている、ということかと存じます。**★

定義書の備考は ★「補足を参照.」★ とあるのみで、★**補足の本文を受領しておりません。**★

★**この判定式が分かれば、当方も同じ定義で日次の判定ができるようになります。**★

### ★★Q11-4. `clean_status_histories.started_at` のほかに、より短い間隔で更新されるテーブル・カラムはございますでしょうか★★

★**新しくお伺いする設問です。**★

★当方は現在、清掃の進み具合を `clean_status_histories` から読んでおります。★
★**これよりも短い間隔で更新される（＝よりリアルタイムに近い）テーブル・カラムがあるので
あれば、お教えください。**★

★**具体的な候補を挙げてお伺いすることは、あえていたしません。**★
★**当方で「このテーブルではないか」と当たりをつけますと、推測が混じります。**★
★**貴社の収集処理が書き込んでいるもののうち、更新間隔が短いものをお示しいただければ、
当方でそれに合わせます。**★

★**あわせて、差し支えなければ次も添えていただけますと助かります。**★

| # | 伺いたいこと |
|---|---|
| ★a★ | ★そのテーブル・カラム名★ |
| ★b★ | ★おおよその更新間隔★（「数秒ごと」「1分ごと」など、おおよそで構いません） |
| ★c★ | ★履歴として積まれるのか、上書きされるのか★ |

★**無い場合は「無い」とお答えいただければ、当方は `clean_status_histories` のままで進めます。**★

## 11-3. ★ご回答がいただけるまでの当方の対応★

★**Q11-2 / Q11-3 のいずれも取れない場合、当方は「出発失敗」と「未実施」を
同じものとして扱います**★（どちらも `clean_error = 1` で判定します）。

★**Q11-4 にご回答がない場合は、`clean_status_histories` を読む現在の形のまま進めます。**★

★**いずれも機能を止めるものではありませんので、ご回答は急ぎません。**★
★**ただ、取れるのであれば取りたい、という性質のものです。**★

---

# 12. ★★DB接続経路について — お願い3件・確認6問★★

★**本章は、第9回の初版（2026-09-15）の末尾に「参考: テスト環境について（申し送り）」として
情報共有のみで記載していた内容を、正式なお願いとして書き直したものです。**★
★**別便にはせず、本書に統合しております。重複はありません。**★

★**お願い（12-3〜12-5）と質問（12-6）を分けて書いております。**★

## 12-1. ★★期限 — ステージングに実データが入る前★★

★**日付ではなく「イベント」で切っております。**★

| 時点 | 状態 | 作り直しのコスト |
|---|---|---|
| ★いま（検証用データのみ）★ | ★実データは入っておりません★ | ★★ほぼゼロ★★。アカウントを作り直しても、失うものがありません |
| ★ステージングに実データが入った後★ | ★★平文の経路を通った資格情報を前提に、運用が始まってしまいます★★ | ★★「作り直す」しか手がなくなります★★ |

★**過ぎるとどうなるか**★ — ★実データ投入後に同じことを行う場合、次が全部必要になります。★

1. ★DBアカウントの再発行★ → ★接続している側（当方のアプリ、貴社のデータ収集処理・集計バッチ）を
   ★**いったん全部止めて**★差し替える必要があります★
2. ★TLS の有効化★ → ★★サーバ再起動を伴う可能性があり、夜間の清掃データ収集を止められません★★
   （D-Watch は★夜間に自動実行された清掃を翌朝確認する運用★です）
3. ★接続元IPの制限★ → ★実データが流れている状態で絞りますと、漏れた接続元から
   データ収集が止まります★

★★つまり「止める調整」が発生します。いまであれば、その調整が要りません。★★
★**だからこそ、実データが入る前にお願いしております。**★

## 12-2. ★実測値（いつ・誰が・どう測ったか）★

★**推測ではありません。実測です。**★

| 項目 | 内容 |
|---|---|
| ★対象★ | ★テスト環境 `133.125.238.144:13306` / DB `clean_watch`★（本書1-1に記載のものと同じサーバーです） |
| ★サーバーのバージョン★ | ★`VERSION() = 10.11.19-MariaDB-ubu2204`★ |
| ★測った人★ | ★DFA（本プロジェクトの作業者）★ |
| ★測った日★ | ★**2026-09-13**★（★2026-09-15 に本書の初版へ転記しました★） |
| ★測り方★ | ★貴社より受領した**参照用アカウント**（`SELECT` のみ）でテスト環境に接続し、★サーバー変数を照会した★ |

| 変数／設定 | 実測値 | 意味 |
|---|---|---|
| `have_ssl` | ★**`DISABLED`**★ | ★サーバーが TLS を提供していません★ |
| `require_secure_transport` | ★**`OFF`**★ | ★暗号化されていない接続を、サーバーが受け付けます★ |
| 参照用アカウントの接続元ホスト | ★**`参照用アカウント@%`**★ | ★`%` は「どこからでも」。接続元の制限がありません★ |

> ★★本章の作成にあたり、テストDBへの再接続は行っておりません（意図的です）★★。
> ★参照専用のアカウントではありますが、接続条件が現在も揃っているかが不明なため★、
> ★★上記は「2026-09-13 に実測された値」です★★。
> ★★すでにご対応済みでしたら、12-3〜12-5 は読み飛ばしてください。★★

★**なぜ問題か**★:

- ★★`have_ssl = DISABLED` と `require_secure_transport = OFF` が重なりますと、接続は必ず平文になります★★。
  ★クライアント側で「TLSを使う」と指定しても、サーバーが提供していないため暗号化されません★
- ★★接続元が `%`（どこからでも）のため、経路は公開IP上にあります★★
- ★この2つが重なりますと、★**DB接続の資格情報が経路上で保護されていない状態**★になります★
- ★★現在は検証用データのみのため実害はありません。問題になるのは実データが入った後です★★

★**なお、このサーバーは弊社（DFA）が契約し、貴社に構築・保守をお願いしているものと
認識しております。**★
★**そのため、実施のご依頼は貴社宛といたしました。この認識に誤りがございましたら、
その旨をお知らせください。**★

## 12-3. ★★お願い1: 接続元の制限（本章の中で最優先です）★★

★`参照用アカウント@%` の `%` を、★**固定IP**★（または閉域ネットワーク内のみ）に絞っていただけますでしょうか。★

### ★なぜ TLS より先にお願いするのか★

★当方が利用しているDB接続用のライブラリに、★**「TLS を有効にしても、条件によっては
接続時の資格情報が経路上に平文で出てしまう」という既知の問題**★が報告されております★
（★当方が 2026-09-16 に自動検査ツールで確認した実測です★）。
★**これは弊社内製アプリケーション側の事情ですので、どう解くかは弊社で判断いたします。
貴社にご対応をお願いするものではありません。**★

★**ただし1点だけ、貴社へのお願いの優先順に関係いたします。**★
★この問題がある間は、★**TLS を有効にしていただいても資格情報が保護されない可能性が残ります**★。
★**そのため当方としては、TLS の有効化よりも先に「経路そのものを閉じる」＝接続元IPの制限の
ほうが効くと考えております。**★
★**恐れ入りますが、12-4（TLS）より 12-3（接続元の制限）を先にご検討いただけますと幸いです。**★

## 12-4. ★お願い2: TLS の有効化★

★`have_ssl` を有効にし、可能であれば `require_secure_transport = ON` にしていただけますでしょうか。★

★**12-3 の後で構いません。**★
★**なお 12-6 の Q12-4 が YES（VMとDBを閉域で結べる）となる場合、本項は不要になる可能性があります。**★

## 12-5. ★★お願い3: 本番用DBアカウントの新規発行★★

★★**本番接続に使うアカウントは、現在のテスト用とは別のものを新規に発行していただけますでしょうか。**★★
★★**ユーザー名・パスワードとも**★★お願いいたします。

### ★理由★

- ★★過去に、実在のDBユーザー名が当方リポジトリのコミットに含まれたことがあります★★
  （★2026-09-10 のコミットで除去済みですが、★**Git の履歴には残っております**★）。
  ★リポジトリは非公開ですが、★**アクセス権を持つ全員が履歴を読めます**★★
- ★★**パスワードは当該コミットには含まれておりません**★★（架空の値のみでした）。
  ★問題はユーザー名が既知になっている点です★
- ★★ユーザー名が既知である以上、12-2 の `参照用アカウント@%`（どこからでも接続可）と組み合わさりますと、
  推測の手間が減ります★★
- ★★あわせて、このアカウントの認証情報は、受け渡しの過程で平文のまま当方側の記録に残っております★★。
  ★この点からも、★**本番用は別の値を新規に発行していただくのが確実**★と考えております★

### ★お願いしていないこと★

- ★**Git 履歴の書き換えはお願いしておりません**★（当方でも実施いたしません）。
  ★**「発行し直す」ほうで解いていただきたい、というお願いです**★
- ★アカウントの発行元は貴社ですので、★**再発行は貴社にしかお願いできません**★

★**タイミングは 12-1 のとおり、★**ステージングに実データが入る前**★です。**★

## 12-6. ★★確認: 本番構成について（6問）★★

★**ここからは質問です。お願いではありません。**★
★**Q12-1 以外は YES / NO でお答えいただけます。**★

### ★なぜお伺いするのか★

★★12-3〜12-5 の解き方（＝「経路を閉じる」）が成立するかどうかが、本番の構成にかかっております★★。

- ★VM と DB が同一の閉域ネットワークに入れるのであれば★ → ★★12-3・12-4 は「初めから起きない」★★
- ★公開IP越しに接続する構成であれば★ → ★★現在の状態がそのまま本番に持ち越されます★★

★**当方は「閉じた構成になる見込み」と考えておりますが、これは当方の読み取りであり、
明示の確認をいただいた記録がございません。**★
★**推測のまま本番に進みますと、12-1 の「作り直し」に直結いたします。**★

### ★当方の現在の理解と、その根拠★

| # | 当方の理解 | 根拠 | 確認の有無 |
|---|---|---|---|
| 1 | 本番のDBは ★MariaDB 10.11★ | ★貴社のご回答（2026-09-10）「本番サーバはMariaDBです」★ | ★★確認済み★★ |
| 2 | DBは ★さくらインターネットのデータベースアプライアンス★ | 同ご回答「さくらインターネットのデータベースアプライアンスはPostgreSQLかMariaDBなので」 | ★★確認済み★★ |
| 3 | アプリは ★さくらのクラウド VM★（Node.js 常駐が必要なため） | ★当方側の想定★ | ★**未確認**★ |
| 4 | ★★「アプリ＝VM」「DB＝アプライアンス」という**別サービスの組み合わせ**である★★ | ★上記2・3からの**読み取り**★ | ★★**未確認**★★ |
| 5 | ★★VM と DB が**同一ネットワークで閉域接続**される★★ | ★当方側の想定★ | ★★**未確認**★★ |

★★すなわち、貴社のご回答は「なぜ MariaDB なのか」のご説明であり、
「本番の構成はこうなります」というご説明ではありませんでした。当方が読み取っただけです。★★
★**そこで、読み取りが合っているかどうかを確認させてください。**★

### ★★Q12-1. アプリサーバー（VM）とDBサーバーは、それぞれどちらが用意する想定でしょうか★★

★**当方の中で理解が揃っておりません。まずここを確定させていただきたく存じます。**★

| # | 対象 | 選択肢 |
|---|---|---|
| ★a★ | ★アプリサーバー（Node.js を載せる VM）★ | ★貴社が用意 / 弊社が用意 / 未定★ |
| ★b★ | ★DBサーバー（データベースアプライアンス）★ | ★貴社が用意 / 弊社が用意 / 未定★ |

★**弊社の記録には「アプリ側は弊社」と読める記述と「貴社に用意していただく」と読める記述が
混在しております。**★
★**どちらが正かは貴社のご認識に合わせますので、お教えください。**★

### ★Q12-2. 本番のDBは、さくらインターネットの★**データベースアプライアンス**★（＝VM上に自前で構築した MariaDB ではない）で間違いないでしょうか★

★YES / NO★

### ★Q12-3. 本番のアプリ（Node.js）は、★**さくらのクラウドの VM**★ に載せる想定で間違いないでしょうか★

★YES / NO★

### ★★Q12-4. その VM と DBアプライアンスは、**同一の閉域ネットワーク（プライベート接続）で結べます**でしょうか★★

★YES / NO★

### ★Q12-5. Q12-4 が YES の場合、★**DB側で公開IPからの接続を完全に閉じることは可能**★でしょうか★

★YES / NO / 条件つき★

### ★Q12-6. Q12-4 が NO の場合（公開IP越しの接続になる場合）、★**TLS を有効にできます**★でしょうか★

★YES / NO / 該当なし★

★**NO や「条件つき」の場合は、差し支えなければ理由を1行だけ添えていただけますと助かります。**★
★**当方はそれを前提に、12-3〜12-5 のお願いの内容を組み直します。**★

## 12-7. ★当方（DFA）側で済ませたこと★

★**丸投げではない、というご説明のために書いております。**★

★2026-09-13 に当方のアプリコードを棚卸しいたしました。★
★★**危険な箇所は1件も見つかっておりません**★★（生SQL 0件 / 並べ替えのカラム名は固定リテラル1箇所 /
`where` にユーザー入力なし / エラー本文に内部情報を載せている箇所 0件 / DBへの書き込み 0件 /
リポジトリ内に実在の認証情報なし）。

★あわせて、生SQL禁止の静的解析ルール化・パスパラメータ検証の全体一致化・CSVの数式インジェクション
対策・本番前セキュリティ確認チェックリストの整備・DBユーザー名の既定値をコードから除去する対応を
済ませております。★

★★問題があるのはコードではなく、DBへ至る「経路」のほうです。そして経路は、当方のコードでは
閉じられません。★★
★**そのため本章の3件を、正式にお願いとしてお渡しいたします。**★

★**ご負担や副作用のご懸念があれば、その旨をお知らせください。当方で別の手を検討します。**★

---

**以上です。ご確認のほど、よろしくお願いいたします。**

★**本改訂で取り下げた項目**★: ★**5章 Q5-1**★（面積の単位。弊社で㎡と確定）/
★**10章**★（DB更新用アカウント。すでに発行済みでした）/ ★**2章 Q2-2**★。

★**取り下げではなく、お伺いする内容を改めた項目**★: ★**11章 Q11-1**★ —
「実際の清掃開始時刻はどこにありますか」→ ★**「`started_at` を使って実装してよろしいでしょうか」**★。
★**こちらはご回答をお願いいたします（A / B の一言で結構です）。**★
★**上の「本改訂で取り下げた項目」については、ご対応は不要です。**★
★**あわせて、テスト環境の「行の中身」を根拠にしていた指摘を取り下げております
（冒頭の「おことわり」をご覧ください）。**★

★**1章（索引）はご対応中と伺いましたので、依頼を取り下げ、参考情報に改めております。**★
★**ご対応が完了しましたら、その旨をお知らせください。当方で `EXPLAIN` を測り直します。**★

★**12章は、期限が「ステージングに実データが入る前」という性質のものです。**★
★**まずは 12-6 の Q12-1〜Q12-6 だけでも先にお答えいただけますと、12-3〜12-5 のお願いの内容を
確定できます。**★
