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

Анатомия игровых лагов › L12 База данных

Запрос без индекса Missing index / full table scan

ID причины db-no-index · Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Инфраструктура БД

Открыть карточку в основной версии с иллюстрациями и экспериментами →

Без индекса, чтобы найти строки по условию, приходится читать всю таблицу (полное сканирование).

Почему С деплоем новой функции появляется поиск по условию, для которого нет индекса → Следствие Сканируются все миллионы строк, один запрос занимает от сотен ms до нескольких секунд → На экране Долго загружаются почта и история обменов, соединения заняты, и в очереди стоят даже другие запросы

Симптомы
Задержка ввода, Ошибка входа / бесконечная загрузка
Факторы
Задержка, Остановка
У кого
Только одна функция, Весь сервер
Когда
При определённом действии
Ответственные
Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Инфраструктура БД
Команда разработки: задачи
Перед деплоем проверять план выполнения новых запросов, добавлять индексы, проверять, что изменяющие запросы (UPDATE, DELETE) тоже используют индекс.
Команда инфраструктуры: задачи
Следить за журналом медленных запросов, находить запросы с полным сканированием и передавать их команде разработки, индексы на работающей БД добавлять онлайн-способом с короткими блокировками.
Цифры для ориентира
С индексом запрос занимает единицы ms, а без индекса замедляется пропорционально объёму данных, на больших таблицах в сотни и даже десятки тысяч раз.
На графике
Ступенька вверх с определённого момента · задержка запросов к БД, число прочитанных строк
Где смотреть
В MySQL смотреть Rows_examined и Rows_sent в slow query log (с включённым log_queries_not_using_indexes туда пишутся и запросы без индекса), SUM_NO_INDEX_USED и SUM_ROWS_EXAMINED в performance_schema events_statements_summary_by_digest и запускать EXPLAIN. В PostgreSQL смотреть seq_scan и seq_tup_read в pg_stat_user_tables и запускать 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) без индекса в некоторых БД блокирует все просканированные строки и может задержать сохранения даже тех игроков, которых этот запрос не касается.

Источники

  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
    seq_scan (число последовательных сканирований) и seq_tup_read (число строк, прочитанных последовательным сканированием) в pg_stat_user_tables
  8. Using EXPLAIN (PostgreSQL Documentation) PostgreSQL
    Seq Scan: план выполнения, при котором по порядку читаются все строки таблицы

Смотрите также

Тот же слой: L12 База данных

Причины с тем же симптомом (Задержка ввода) на других слоях

Карточка в основной версии с иллюстрациями и экспериментами