한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

遊戲 Lag 白皮書 › L12 資料庫

沒有索引的查詢 Missing index / full table scan

原因 ID db-no-index · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)

在含圖解與實驗的完整版中開啟卡片 →

沒有索引時,要找出符合條件的資料列,就必須讀完整張資料表(全表掃描)。

為什麼 部署新功能時,加入了沒有索引的條件查詢 → 於是 掃描數百萬筆資料列,一個查詢就要數百 ms~數秒 → 畫面上 信箱、交易紀錄載入變慢,連線被占住,連其他請求也要等待

症狀
輸入延遲, 連不上/無限讀取
因素
延遲, 停滯
誰會遇到
只有特定功能, 整個伺服器
何時
做特定動作時
負責單位
主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事
新查詢在部署前先檢查執行計畫、加上索引,並確認修改資料的查詢(UPDATE、DELETE)也有用到索引。
基礎設施團隊要做的事
監看慢查詢 log,找出全表掃描的查詢並提供給遊戲開發團隊;營運中新增索引時,採用鎖定時間短的線上(online)方式。
數值參考
有索引時只要數 ms;沒有索引時會隨資料量等比例變慢,在大型資料表上會慢到數百~數萬倍。
圖表上
從某個時間點起階梯式上升 · DB 查詢延遲、讀取的資料列數
查看位置
MySQL 看 slow query log(開啟 log_queries_not_using_indexes 後,沒用到索引的查詢也會記錄)的 Rows_examined、Rows_sent,以及 performance_schema events_statements_summary_by_digest 的 SUM_NO_INDEX_USED、SUM_ROWS_EXAMINED,再執行 EXPLAIN。PostgreSQL 看 pg_stat_user_tables 的 seq_scan、seq_tup_read,再執行 EXPLAIN
符合的跡象
部署後新出現的查詢,讀取的資料列(Rows_examined)比回傳的(Rows_sent)多出數千倍,EXPLAIN 顯示全表掃描(MySQL type ALL、PostgreSQL Seq Scan)。大型資料表的 seq_tup_read 從部署時間點起急遽增加
不符合的跡象
有用到索引仍然很慢時,是鎖定等待(db-hot-row、db-ddl-lock)或執行計畫改變(db-plan-flip)。小型資料表的全表掃描可能是正常的
確認方式
用基礎設施工具確認(不需要遊戲程式碼)
深入了解
受影響的不只是讀取。沒有索引的修改查詢(UPDATE、DELETE)依 DB 不同,可能把掃描過的資料列全都鎖住,連無關玩家的存檔都會被擋住。

出處

  1. How MySQL Uses Indexes MySQL
    沒有索引時會從第一筆資料列開始讀完整張資料表,資料表越大成本越高
  2. Locks Set by Different SQL Statements in InnoDB MySQL
    沒有合適的索引而掃描整張資料表時,所有資料列都會被鎖住,連其他使用者新增資料都會被擋住
  3. The Slow Query Log MySQL
    記錄超過 long_query_time(預設 10 秒)的查詢,也可以另外記錄沒有使用索引的查詢
  4. CREATE INDEX (PostgreSQL Documentation) PostgreSQL
    加上 CONCURRENTLY 建立索引時不會擋住寫入;一般的建立方式會擋住寫入直到完成
  5. Statement Summary Tables MySQL
    events_statements_summary_by_digest:依相同形式的查詢彙總 SUM_NO_INDEX_USED(未使用索引執行的次數)、SUM_ROWS_EXAMINED
  6. EXPLAIN Output Format MySQL
    type 為 ALL 表示全表掃描,通常以新增索引來避免
  7. The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
    pg_stat_user_tables 的 seq_scan(循序掃描次數)、seq_tup_read(循序掃描讀取的資料列數)
  8. Using EXPLAIN (PostgreSQL Documentation) PostgreSQL
    Seq Scan:依序讀取資料表所有資料列的執行計畫

相關原因

同一層:L12 資料庫

同一症狀(輸入延遲)在其他層的原因

查看含圖解與實驗的完整版卡片