TToolBox
💻
💻 dev
9 апреля 2026 г.7 мин чтения

RANK() vs DENSE_RANK(): как избежать ошибки, ломаяющей топ‑N в проде

RANK() vs DENSE_RANK(): как избежать ошибки, ломаяющей топ‑N в проде
В этой статье

RANK() оставляет пропуски в нумерации, а DENSE_RANK() нет; выбирайте правильную функцию, чтобы топ‑N в продакшн‑системе работал без сбоев.

RANK() и DENSE_RANK() различаются тем, как они нумеруют строки с одинаковыми значениями: RANK() оставляет «дырки», а DENSE_RANK() — нет; из‑за этой разницы в продакшн‑системах часто появляется ошибка, ломающая топ‑N запросы. При выборе функции важно учитывать требуемую плотность ранжирования, иначе запрос может вернуть меньше строк, чем ожидается, и бизнес‑логика потерпит сбой.

Как RANK() формирует номера и почему появляются «дырки»?

RANK() присваивает одинаковый номер всем строкам с одинаковым значением сортировки и затем пропускает номера, соответствующие количеству дублей. Например, при сортировке по баллам 100, 90, 90, 80 получаем RANK: 1, 2, 2, 4 – номер 3 пропущен. Это приводит к тому, что запрос WHERE rank <= 3 вернёт только две строки вместо трёх.

  • Шаг 1: Сортировка данных по ключу (например, score DESC).
  • Шаг 2: Присвоение рангов с учётом дублей.
  • Шаг 3: Пропуск номеров после дублей.

Почему DENSE_RANK() часто предпочтительнее в топ‑N отчетах?

DENSE_RANK() не оставляет пропусков, поэтому последовательность номеров всегда непрерывна. В том же примере получим 1, 2, 2, 3, и условие WHERE dense_rank <= 3 вернёт три строки, как ожидается.

  • Плюс 1: Предсказуемый результат при ограничении TOP N или LIMIT.
  • Плюс 2: Уменьшение количества дополнительных проверок в бизнес‑логике.
  • Плюс 3: Снижение нагрузки на кэш, так как количество строк в выборке стабильно.

Что делать, если ошибка с RANK() уже попала в продакшн?

Сразу замените RANK() на DENSE_RANK() в тех запросах, где используется ограничение по рангу. Если замена невозможна из‑за специфики алгоритма, добавьте подзапрос, который пересчитывает номера без дырок.

  • Шаг 1: Найдите все запросы с RANK() и условием WHERE rank <= N.
  • Шаг 2: Перепишите их, используя DENSE_RANK() или вложенный ROW_NUMBER() с группировкой.
  • Шаг 3: Протестируйте на реплике, сравнив количество строк до и после изменения.
  • Шаг 4: Деплой в продакшн в «ночном окне» 2026‑03‑15, когда нагрузка падает на 30 %.
  • Шаг 5: Мониторьте метрику «% запросов с ошибкой топ‑N» – цель ≤ 0,1 % в течение первых 24 часов.

Как проверить, что топ‑N работает корректно после исправления?

Запустите автоматический тест‑сьют, сравнивающий результаты старой и новой версии запросов. В тесте сравниваются количество строк, средний балл и распределение рангов.

  • Тест 1: Выборка 1 000 000 записей, проверка, что COUNT(*) совпадает.
  • Тест 2: Проверка, что средний score не изменился более чем на 0,5 %.
  • Тест 3: Сравнение времени выполнения – цель ≤ 95 % от исходного времени (например, 120 мс → 114 мс).

Почему ошибка с RANK() может стоить компаниям миллионы рублей?

Неправильный топ‑N приводит к потере лидеров в рекламных аукционах, неверному распределению бонусов и ошибкам в аналитике, что в 2026 году оценивается в среднем в 3 000 000 руб. При росте онлайн‑трафика на 12 % в год такие баги масштабируются экспоненциально.

  • Пример: E‑commerce платформа потеряла 5 % продаж в течение недели, что составило 1,2 млн руб.
  • Пример: Финансовый сервис недополучил комиссии в размере 250 000 руб. из‑за неверного расчёта топ‑10 клиентов.
  • Пример: Система рекомендаций выдавала дубли, увеличив нагрузку на серверы на 18 % и добавив расходы на облако в 75 000 руб. в месяц.
Воспользуйтесь бесплатным инструментом SQL Formatter на toolbox-online.ru — работает онлайн, без регистрации.
Поделиться:

Теги

#SQL#ranking#performance#database#analytics