MRRARRNRRSaaS-метрикиSQL

MRR, ARR, NRR: метрики подписки и формулы

2026-07-10 12 мин

Коротко: MRR (Monthly Recurring Revenue) — сумма регулярной месячной выручки со всех активных подписок на конкретную дату. Считается как сумма нормализованных к месяцу платежей: годовой тариф делишь на 12, квартальный на 3. ARR — это просто MRR × 12. NRR (Net Revenue Retention) показывает, как изменилась выручка старой когорты клиентов за период БЕЗ учёта новых: NRR = (MRR начала + Expansion − Contraction − Churn) / MRR начала × 100%. NRR выше 100% означает, что бизнес растёт даже если вообще перестанет продавать новым клиентам.

Ниже — три метрики на одном сквозном примере: разложение MRR по компонентам движения, переход к ARR, правильный расчёт NRR и готовые SQL-запросы по таблице подписок.

Что такое MRR и из каких компонентов он состоит?

MRR — это моментальный снимок регулярной выручки. Ключевое слово — «регулярной»: разовые платежи (setup fee, консалтинг, штрафы) в MRR не входят, потому что они не повторяются каждый месяц и портят прогнозируемость.

Главная ловушка новичков — считать MRR как «выручку за месяц по кассе». Это неверно. Если клиент платит 12 000 ₽ за год вперёд, его вклад в MRR — не 12 000 ₽ в месяц оплаты и не 0 ₽ в остальные, а 12000 / 12 = 1000 ₽ каждый месяц действия подписки. MRR нормализует все тарифы к общему знаменателю — одному месяцу.

Нормализация по типам тарифов:

Общий MRR на дату — это сумма нормализованных вкладов всех активных подписок. Тесно связанная метрика — ARPU: ARPU = MRR / число активных подписчиков. Если хотите разобраться, чем ARPU отличается от ARPPU, есть отдельный разбор в статье про ARPU и ARPPU.

Как разложить движение MRR на New, Expansion, Contraction, Churn?

Абсолютное значение MRR полезно, но менеджмент и инвесторы смотрят на движение — из чего сложилось изменение между двумя датами. Это называется MRR movement или MRR bridge, и оно раскладывается на пять компонентов.

КомпонентЧто этоЗнак
New MRRВыручка от клиентов, которых в прошлом периоде не было+
Expansion MRRРост по существующим клиентам (апгрейд тарифа, доп. места)+
Reactivation MRRВернувшиеся после оттока клиенты+
Contraction MRRУменьшение по существующим (даунгрейд, меньше мест)
Churned MRRПолностью ушедшие клиенты

Формула моста между периодами:

MRR_конец = MRR_начало + New + Expansion + Reactivation − Contraction − Churned

Пример на числах. Стартовали месяц с MRR = 1 000 000 ₽. За месяц:

Считаем: 1 000 000 + 150 000 + 80 000 + 10 000 − 30 000 − 120 000 = 1 090 000 ₽.

Почему это важнее одного числа: два бизнеса могут иметь одинаковый прирост +90 000 ₽, но у первого он держится на бешеном New при огромном Churn (дырявое ведро), а у второго — на здоровом Expansion при почти нулевом оттоке. Второй бизнес намного устойчивее, хотя итоговая цифра совпадает. Отдельно за оттоком стоит следить через churn rate — про его расчёт в SQL есть подробный разбор оттока клиентов.

Как из MRR получить ARR?

Самая простая формула во всей статье: ARR = MRR × 12.

ARR (Annual Recurring Revenue) — годовая версия того же показателя. Её берут, потому что в enterprise-сегменте контракты годовые, а инвесторы мыслят годовыми масштабами: «компания на 24 млн ARR» звучит и сравнивается легче, чем «на 2 млн MRR».

Три важных нюанса, на которых спотыкаются:

Для компонентов движения действует то же правило: New ARR = New MRR × 12 и так далее. Аналитику это удобно — декомпозиция один раз считается в месячных величинах, а презентуется в годовых.

Что показывает NRR и как его правильно считать?

NRR (Net Revenue Retention), он же NDR (Net Dollar Retention) — процент выручки, удержанной от когорты существующих клиентов за период, с учётом расширений и оттока, но БЕЗ новых клиентов. Это, пожалуй, главная метрика зрелого SaaS.

Формула:

NRR = (MRR_начало + Expansion − Contraction − Churned) / MRR_начало × 100%

Критично: в числитель НЕ входит New MRR. Мы измеряем судьбу денег, которые уже были у нас в начале периода. Новые клиенты — это отдельная история роста, они не должны маскировать проблемы с удержанием базы.

Пример по нашим числам выше. Берём только старую когорту (без New = 150 000):

NRR = (1 000 000 + 80 000 + 10 000 − 30 000 − 120 000) / 1 000 000 × 100%
    = 940 000 / 1 000 000 × 100% = 94%

NRR = 94% означает: если бы мы вообще не продавали новым, выручка от старой базы за месяц сократилась бы на 6%. Рядом полезно держать GRR (Gross Revenue Retention) — то же самое, но без Expansion в числителе:

GRR = (MRR_начало − Contraction − Churned) / MRR_начало × 100%

GRR всегда ≤ NRR и ≤ 100%, потому что не даёт расширениям «замазать» потери. Разрыв между NRR и GRR показывает, насколько сильно апселлы компенсируют отток. NRR тесно связан с retention на уровне пользователей, но считается в деньгах, а не в головах — про пользовательский retention есть отдельная статья про кривую удержания.

Какие нормы NRR считаются здоровыми в 2026 году?

Ориентиры зависят от сегмента, но общая шкала для B2B SaaS выглядит так:

NRRОценкаТипичный сегмент
< 90%Проблема: база утекает быстрее, чем растётСлабый PMF, высокий отток
90–100%Нормально для SMB / self-serveМассовый B2C-подобный SaaS
100–110%Хорошо: база сама растётКрепкий продукт с апселлом
110–125%ОтличноЗрелый B2B с seat-expansion
> 125%Топ-квартильUsage-based pricing, enterprise

Общие закономерности рынка (обобщённые оценки, не привязанные к конкретному источнику):

Важнее абсолютного числа — тренд. NRR, стабильно ползущий вниз квартал за кварталом, — ранний сигнал усталости продукта, даже если New MRR пока перекрывает потери. На собеседованиях аналитика этот вопрос любят: если готовитесь, загляните в банк вопросов по метрикам и потренируйте формулировки на AI-собесе.

Как посчитать MRR и NRR SQL-запросом по подпискам?

Возьмём типичную таблицу подписок. Один ряд — одна активная версия подписки с периодом действия и месячной нормализованной ценой.

-- subscriptions
-- subscription_id | customer_id | mrr_amount | started_at | ended_at (NULL = активна)

MRR на конкретную дату — сумма mrr_amount по подпискам, активным на эту дату:

SELECT SUM(mrr_amount) AS mrr
FROM subscriptions
WHERE started_at <= DATE '2026-06-01'
  AND (ended_at IS NULL OR ended_at > DATE '2026-06-01');

Теперь декомпозиция движения между двумя месяцами. Считаем MRR каждого клиента на начало и конец периода, а затем классифицируем по компонентам через FULL OUTER JOIN:

WITH start_mrr AS (
    SELECT customer_id, SUM(mrr_amount) AS mrr
    FROM subscriptions
    WHERE started_at <= DATE '2026-05-01'
      AND (ended_at IS NULL OR ended_at > DATE '2026-05-01')
    GROUP BY customer_id
),
end_mrr AS (
    SELECT customer_id, SUM(mrr_amount) AS mrr
    FROM subscriptions
    WHERE started_at <= DATE '2026-06-01'
      AND (ended_at IS NULL OR ended_at > DATE '2026-06-01')
    GROUP BY customer_id
),
movement AS (
    SELECT
        COALESCE(s.customer_id, e.customer_id) AS customer_id,
        COALESCE(s.mrr, 0) AS start_mrr,
        COALESCE(e.mrr, 0) AS end_mrr
    FROM start_mrr s
    FULL OUTER JOIN end_mrr e ON s.customer_id = e.customer_id
)
SELECT
    SUM(CASE WHEN start_mrr = 0 AND end_mrr > 0
             THEN end_mrr END)                              AS new_mrr,
    SUM(CASE WHEN start_mrr > 0 AND end_mrr > start_mrr
             THEN end_mrr - start_mrr END)                  AS expansion_mrr,
    SUM(CASE WHEN start_mrr > 0 AND end_mrr < start_mrr AND end_mrr > 0
             THEN start_mrr - end_mrr END)                  AS contraction_mrr,
    SUM(CASE WHEN start_mrr > 0 AND end_mrr = 0
             THEN start_mrr END)                            AS churned_mrr,
    SUM(start_mrr) AS total_start_mrr,
    SUM(end_mrr)   AS total_end_mrr
FROM movement;

Из этих агрегатов NRR считается одной строкой поверх результата:

-- NRR = (start + expansion − contraction − churned) / start
SELECT ROUND(
    (total_start_mrr + expansion_mrr - contraction_mrr - churned_mrr)
    / total_start_mrr * 100, 1
) AS nrr_pct
FROM (/* подзапрос из декомпозиции выше */) m;

Тот же подход на pandas, если данные лежат в DataFrame, — сгруппировать по клиенту на две даты, сджойнить и классифицировать через numpy.select:

import pandas as pd
import numpy as np

def customer_mrr(df, snapshot):
    active = df[(df["started_at"] <= snapshot) &
               ((df["ended_at"].isna()) | (df["ended_at"] > snapshot))]
    return active.groupby("customer_id")["mrr_amount"].sum()

start = customer_mrr(subs, "2026-05-01").rename("start_mrr")
end   = customer_mrr(subs, "2026-06-01").rename("end_mrr")

m = pd.concat([start, end], axis=1).fillna(0)

cond = [
    (m.start_mrr == 0) & (m.end_mrr > 0),
    (m.start_mrr > 0) & (m.end_mrr > m.start_mrr),
    (m.start_mrr > 0) & (m.end_mrr < m.start_mrr) & (m.end_mrr > 0),
    (m.start_mrr > 0) & (m.end_mrr == 0),
]
m["bucket"] = np.select(cond, ["new", "expansion", "contraction", "churned"],
                        default="flat")

s = m.start_mrr.sum()
expansion   = (m.end_mrr - m.start_mrr).where(m.bucket == "expansion", 0).sum()
contraction = (m.start_mrr - m.end_mrr).where(m.bucket == "contraction", 0).sum()
churned     = m.start_mrr.where(m.bucket == "churned", 0).sum()

nrr = (s + expansion - contraction - churned) / s * 100
print(round(nrr, 1))

Разобрать оба запроса построчно и покрутить их на живых данных удобнее в SQL-тренажёре и Python-тренажёре — там настоящий PostgreSQL и Pyodide прямо в браузере. Если window-функции и FULL OUTER JOIN пока в новинку, начните с базового курса SQL.

Какие ошибки чаще всего искажают MRR и NRR?

Даже с правильными формулами цифры легко испортить на этапе подготовки данных. Вот типичные грабли, на которые наступают аналитики.

Дисциплина на этапе очистки данных важнее красоты формулы: почти все расхождения в MRR-отчётах — это не математика, а грязный источник. Потренировать типовые запросы на чистку и агрегацию можно в тренажёре, а разобрать смежные подводные камни — в статье про антипаттерны SQL.

Почему NRR выше 100% означает рост без новых клиентов?

Разберём на пределе. Представьте, что маркетинг остановлен: ни одного нового клиента. Что произойдёт с выручкой?

Ответ полностью определяется NRR. При NRR = 100% выручка стоит на месте — расширения ровно компенсируют отток. При NRR = 115% выручка растёт на 15% за период сама собой: существующие клиенты докупают места и апгрейдят тарифы быстрее, чем уходят их соседи по когорте.

Это свойство делает NRR > 100% «святым Граалем» SaaS. Такой бизнес обладает встроенным маховиком роста: даже при полной остановке привлечения выручка увеличивается. А каждый рубль, потраченный на New, ложится сверху уже растущей базы, а не латает дыры оттока.

Простая иллюстрация накопления при NRR = 115% и нулевом New:

Именно поэтому NRR — сильнейший предиктор долгосрочной стоимости компании и один из главных драйверов LTV. Высокий NRR удлиняет жизнь клиента и увеличивает выручку с него, что напрямую улучшает юнит-экономику. Как NRR встраивается в LTV/CAC/payback, детально разобрано в материале по unit-экономике SaaS, а базовые понятия CM1/CM2 — в статье про юнит-экономику простыми словами.

Что стоит унести с собой:

Лучший способ закрепить — написать декомпозицию MRR своими руками по реальной таблице подписок. Первые 5 задач в тренажёре открыты бесплатно, дальше доступ по Pro. Соберёте MRR-bridge и NRR за один вечер — и на собеседовании этот блок вопросов уже не застанет врасплох.

Разложи MRR SQL-запросом сам
5 задач по SQL и подпискам бесплатно, дальше Pro. Настоящий PostgreSQL в браузере — пиши декомпозицию MRR и проверяй результат мгновенно.
Открыть SQL-тренажёр →