Без индекса, чтобы найти строки по условию, приходится читать всю таблицу (полное сканирование).
Почему С деплоем новой функции появляется поиск по условию, для которого нет индекса → Следствие Сканируются все миллионы строк, один запрос занимает от сотен 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) без индекса в некоторых БД блокирует все просканированные строки и может задержать сохранения даже тех игроков, которых этот запрос не касается.
Источники
How MySQL Uses IndexesMySQL Без индекса БД читает всю таблицу с первой строки, и чем больше таблица, тем дороже запрос
Locks Set by Different SQL Statements in InnoDBMySQL Если подходящего индекса нет и таблица сканируется целиком, блокируются все строки, и другие пользователи не могут даже добавлять записи
The Slow Query LogMySQL Запись запросов дольше long_query_time (по умолчанию 10 секунд), отдельно можно записывать и запросы, которые не используют индекс
Statement Summary TablesMySQL events_statements_summary_by_digest: по каждому шаблону запроса SUM_NO_INDEX_USED (сколько раз он выполнялся без индекса) и SUM_ROWS_EXAMINED
EXPLAIN Output FormatMySQL type ALL означает полное сканирование таблицы, обычно его устраняют добавлением индекса