diff --git a/docs/adr-003-hot-vs-entity.md b/docs/adr-003-hot-vs-entity.md new file mode 100644 index 0000000..5486434 --- /dev/null +++ b/docs/adr-003-hot-vs-entity.md @@ -0,0 +1,78 @@ +# ADR-003:Hot zone 與 Entity 表收斂 + +- **狀態**:已接受(2026-09-26,選項 A) +- **日期**:2026-09-26 +- **相關**:`BENCHMARK-SCALE.md`(O-3、O-5)、backlog PR-025〜PR-030 + +## 背景 + +post 的高頻欄位有兩套扁平化機制,資料可能存兩份: + +| | Hot zone | Entity bridge | +|---|---|---| +| 表 | `wp_wpdo_hot_{post_type}`(每個 post type 一張) | `wp_wpdo_post_{group}`(每個群組一張) | +| 註冊 | `TMDO_Schema_Registry`(zone = hot) | `TMDO_Entity_Registry::register_group()` | +| 寫入 | `TMDO_Sync_Bridge`(zone 模組進入 dual_write 後) | `TMDO_Hook_Bus`(實體 mode ≥ dual_write) | +| 查詢改寫 | `TMDO_Query_Router`(`hot_*` 模組 cutover 後) | `TMDO_Post_Query_Router`(post mode ≥ shadow_read) | +| 生命週期 | 每個 zone 模組 7 狀態 FSM | 每個實體 4 模式(disabled → aeav_only) | +| 涵蓋實體 | 只有 post | post、user、term、comment | +| 可完全取代原生 meta | 否(cutover 後原生仍保留) | 是(aeav_only) | +| 其他 | 單欄 `indexed`、自訂 `data_type` | post_type 範圍(PR-033)、schema hash、衝突偵測、孤兒還原、回寫原生(PR-017/018/031) | + +Warm(瀏覽數 TTL)、Cold(JSON blob)、Archive(已刪除文章的 meta)是 Entity 沒有的能力,**不在本決策範圍**,保持原狀。 + +## 事實 + +**效能**(100k vendor / 1M listing,`BENCHMARK-SCALE.md`): + +| 情境 | Hot | Entity | +|---|---:|---:| +| 價格區間搜尋 p50 | 558 ms | 652 ms | +| 價格區間 + verified p50 | **277 ms**(有複合索引) | 337 ms | +| vendor 名下 listing p50 | 3,405 ms(無索引) | **0.28 ms** | +| 單筆 / 列表預載 | 相同 | 相同 | +| 容量 | 229 MB | 379 MB | + +唯一 Hot 領先的是有複合索引的情境;Entity 支援複合索引後(PR-027)即可追平。 + +**各站使用現況**(2026-09-26 唯讀查詢): + +| 站 | Hot / Cold 表 | zone 模組 | post entity | +|---|---|---|---| +| dev20 / dev21 / dev22 | 無 | 全 idle | aeav_only(dev21 約 400 萬列) | +| dev23 / 24 / 30 / 31 / 40 | 無 | 全 idle | disabled | +| dev34(舊 WPDO 1.3.37) | hot_hp_listing 486、hot_hp_vendor 233 | cutover | disabled | +| dev10 DB(舊版) | hot_hp_listing 491、hot_hp_vendor 231 | cutover | aeav_only(約 3,900 列) | + +- **沒有任何 2meet-DO 站在用 Hot zone**;有扁平資料的站全部走 Entity。 +- 只有兩個舊系統的站有 Hot 資料,而它們在 cutover 仍雙寫 postmeta,Hot 表只是副本(PR-022 已確認以 postmeta 為準)。 + +**只由 Hot zone 註冊、Entity 群組沒有涵蓋的 HP 欄位**:listing / request 的 `hp_drafted`;bookings 的 `hp_start_time`、`hp_end_time`、`hp_quantity`;memberships 的 `hp_expire_period`、`hp_primary`、`hp_expired_time`。 + +## 選項 + +**A. 收斂到 Entity(建議)** +post 高頻欄位只用 Entity。Hot zone 凍結:不再新增註冊,程式碼暫留只為讀取舊資料,確認沒有站使用後再移除。 + +- 優點:一套路由、一份資料;Entity 能力是 Hot 的超集;現況已經全部在用 Entity,不需要搬資料。 +- 代價:Hot 獨有的欄位(上面那幾個)要改成新的 Entity 群組;情境 2 要靠 PR-027 的複合索引追平。 + +**B. 兩套並存** +維持現狀。代價是兩套寫入和查詢路徑都要維護,同一個 key 可能存兩份,O-3 之類的最佳化要做兩次。 + +**C. 收斂到 Hot** +不可行:Hot 只支援 post,也沒有 aeav_only、範圍宣告、回寫工具。 + +## 建議(選項 A)的後續步驟 + +1. **PR-026(Hot 表 bigint 索引)標為 `[!]` 不做**:沒有站在用 Hot zone。 +2. **PR-027(Entity 複合索引)照常做**:這是情境 2 追平 Hot 的方式。 +3. **新增 PR(HP AddOn)**:把 Hot 獨有的欄位改註冊成新的 Entity 群組(例如 `hp_booking_core`、`hp_membership_core`,以及 listing / request 的補充群組);既有群組的定義不能改。 +4. **新增 PR(HP AddOn)**:HP adapter 停止註冊 hot 欄位;核心對 zone = hot 的新註冊記錄 deprecated 警告。 +5. **之後**:dev34(PR-022)和 dev10 DB(PR-023)遷出後,再評估移除 `TMDO_Zone_Hot`、`TMDO_Sync_Bridge` 的 hot 路徑與 `TMDO_Query_Router`。 + +## 決定 + +**選項 A:收斂到 Entity。**(使用者 2026-09-26 決定) + +Hot zone 凍結,依上面的後續步驟執行;backlog 已同步調整(PR-026 標為 `[!]`,新增 HP AddOn 的兩個 PR)。