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

Sách trắng lag game › L12 Cơ sở dữ liệu

Query không có index Missing index / full table scan

ID nguyên nhân db-no-index · Phụ trách chính Phát triển server (Đội phát triển game) · Phối hợp Hạ tầng DB (Đội hạ tầng)

Mở thẻ gốc có hình minh họa và thí nghiệm →

Không có index thì muốn tìm các dòng thỏa điều kiện, DB phải đọc toàn bộ bảng (full scan).

Vì sao Tính năng mới được triển khai, kèm truy vấn theo điều kiện không có index → Dẫn đến Quét toàn bộ hàng triệu dòng, một query mất từ vài trăm ms đến vài giây → Trên màn hình Hộp thư và lịch sử giao dịch tải chậm, kết nối DB bị giữ khiến các yêu cầu khác cũng phải chờ

Triệu chứng
Trễ thao tác, Không vào được·kẹt loading
Yếu tố
Độ trễ, Ngưng trệ
Ai gặp phải
Chỉ một tính năng, Cả server
Khi nào
Khi làm một thao tác nhất định
Phụ trách
Phụ trách chính Phát triển server (Đội phát triển game) · Phối hợp Hạ tầng DB (Đội hạ tầng)
Việc cần làm (Đội phát triển game)
Xem xét kế hoạch thực thi của query mới trước khi triển khai, thêm index, kiểm tra cả query sửa dữ liệu (UPDATE, DELETE) có dùng index không.
Việc cần làm (Đội hạ tầng)
Theo dõi slow query log, tìm query full scan và chia sẻ cho đội phát triển game, khi đang vận hành thì thêm index theo cách online để thời gian khóa ngắn.
Con số tham khảo
Có index thì mất vài ms; không có thì chậm dần theo kích thước dữ liệu, với bảng lớn có thể chậm gấp vài trăm đến vài chục nghìn lần.
Trên đồ thị
Tăng như bậc thang từ một thời điểm · Độ trễ query DB, số dòng đã đọc
Chỗ cần xem
MySQL: xem Rows_examined, Rows_sent trong slow query log (bật log_queries_not_using_indexes thì cả query không dùng index cũng được ghi), SUM_NO_INDEX_USED, SUM_ROWS_EXAMINED trong performance_schema events_statements_summary_by_digest, rồi chạy EXPLAIN. PostgreSQL: xem seq_scan, seq_tup_read trong pg_stat_user_tables, rồi chạy EXPLAIN
Đúng nếu
query mới xuất hiện sau khi triển khai đọc số dòng (Rows_examined) nhiều gấp hàng nghìn lần số dòng trả về (Rows_sent), EXPLAIN cho thấy quét toàn bộ bảng (MySQL type ALL, PostgreSQL Seq Scan). seq_tup_read của bảng lớn tăng dốc kể từ lúc triển khai
Loại trừ nếu
có dùng index mà vẫn chậm → chờ khóa (db-hot-row, db-ddl-lock) hoặc kế hoạch thực thi thay đổi (db-plan-flip). Quét toàn bộ bảng nhỏ có thể là bình thường
Cách kiểm tra
Kiểm tra bằng công cụ hạ tầng (không cần code game)
Tìm hiểu thêm
Không chỉ việc đọc bị chậm. Tùy DB, query sửa dữ liệu (UPDATE, DELETE) chạy không có index có thể khóa cả những dòng đã quét qua, chặn luôn việc lưu dữ liệu của những người chơi không liên quan.

Nguồn

  1. How MySQL Uses Indexes MySQL
    Không có index thì phải đọc toàn bộ bảng từ dòng đầu tiên, bảng càng lớn chi phí càng cao
  2. Locks Set by Different SQL Statements in InnoDB MySQL
    Không có index phù hợp nên phải quét toàn bộ bảng thì mọi dòng đều bị khóa, chặn cả việc thêm dòng của người dùng khác
  3. The Slow Query Log MySQL
    Ghi các query vượt long_query_time (mặc định 10 giây), có thể ghi riêng cả các query không dùng index
  4. CREATE INDEX (PostgreSQL Documentation) PostgreSQL
    Tạo bằng CONCURRENTLY thì tạo được index mà không chặn thao tác ghi, cách tạo thông thường chặn ghi cho đến khi xong
  5. Statement Summary Tables MySQL
    events_statements_summary_by_digest: SUM_NO_INDEX_USED (số lần chạy không dùng index) và SUM_ROWS_EXAMINED theo từng dạng query
  6. EXPLAIN Output Format MySQL
    type là ALL nghĩa là quét toàn bộ bảng, thường tránh bằng cách thêm index
  7. The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
    seq_scan (số lần quét tuần tự) và seq_tup_read (số dòng đọc bằng quét tuần tự) trong pg_stat_user_tables
  8. Using EXPLAIN (PostgreSQL Documentation) PostgreSQL
    Seq Scan: kế hoạch thực thi đọc lần lượt mọi dòng của bảng

Nguyên nhân nên xem cùng

Cùng tầng: L12 Cơ sở dữ liệu

Nguyên nhân ở tầng khác gây cùng triệu chứng (Trễ thao tác)

Xem thẻ gốc có hình minh họa và thí nghiệm