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

ゲームラグ白書 › L12 データベース

インデックスのないクエリ Missing index / full table scan

原因ID db-no-index · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・DBインフラ

図と実験のあるメインページでこのカードを開く →

インデックスがないと、条件に合う行を探すためにテーブル全体を読む必要があります(フルスキャン)。

なぜ 新機能のデプロイで、インデックスのない条件検索が追加される → すると 数百万行をすべてスキャンし、クエリ1つに数百ms〜数秒 → 画面では 郵便受け・取引履歴のロード遅延、コネクションがふさがって他の要求まで待たされる

症状
入力遅延, 接続不可・無限ロード
要因
遅延, ストール
誰に起きるか
特定の機能だけ, サーバー全体
いつ
特定の操作をしたとき
担当
主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・DBインフラ
ゲーム開発チームの対応
新しいクエリはデプロイ前に実行計画をレビュー、インデックスの追加、更新系のクエリ(UPDATE・DELETE)もインデックスが効くか確認。
インフラチームの対応
スロークエリログの監視、フルスキャンのクエリを見つけてゲーム開発チームに共有、運用中のインデックス追加はロックの短いオンライン方式で適用。
数値の目安
インデックスがあれば数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_sent)より数千倍多い行を読み(Rows_examined)、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 データベース

同じ症状(入力遅延)を起こすほかの層の原因

図と実験のあるメインページでこのカードを見る