Как посчитать contraction MRR в SQL
Содержание:
Зачем contraction MRR
Contraction MRR — снижение revenue существующих customers без полного оттока: downgrade плана, уменьшение seats, переход с annual на monthly. Часто скрыт за общим churn, хотя сигнализирует совсем о другом: «продукт ещё нужен, но дешевле». Реакция: review цен, оптимизация для среднего сегмента.
Contraction vs churn
| Метрика | Что произошло |
|---|---|
| Churn | Customer ушёл полностью, MRR = 0 |
| Contraction | Customer остался, MRR упал, но > 0 |
| Expansion | Customer остался, MRR вырос |
Contraction в SQL
WITH start_state AS (
SELECT customer_id, mrr AS start_mrr
FROM subscription_state
WHERE state_date = '2026-04-01' AND status = 'active'
),
end_state AS (
SELECT customer_id, mrr AS end_mrr
FROM subscription_state
WHERE state_date = '2026-05-01' AND status = 'active'
),
both AS (
SELECT
s.customer_id,
s.start_mrr,
e.end_mrr,
s.start_mrr - e.end_mrr AS contraction_amount
FROM start_state s
JOIN end_state e USING (customer_id)
WHERE e.end_mrr < s.start_mrr
)
SELECT
COUNT(*) AS contracting_customers,
SUM(contraction_amount) AS total_contraction_mrr,
AVG(contraction_amount) AS avg_contraction_per_customer,
AVG(contraction_amount::NUMERIC / NULLIF(start_mrr, 0)) * 100 AS avg_pct_lost
FROM both;JOIN ... USING отсекает churned (end_state IS NULL).
По типу contraction
WITH state_change AS (
SELECT
customer_id,
plan_at_start,
plan_at_end,
seats_at_start,
seats_at_end,
mrr_at_start,
mrr_at_end,
CASE
WHEN plan_at_end <> plan_at_start AND mrr_at_end < mrr_at_start THEN 'plan_downgrade'
WHEN seats_at_end < seats_at_start AND plan_at_end = plan_at_start THEN 'seat_reduction'
WHEN mrr_at_end < mrr_at_start THEN 'usage_decline'
ELSE 'no_contraction'
END AS contraction_type
FROM monthly_customer_snapshot
)
SELECT
contraction_type,
COUNT(*) AS customers,
SUM(mrr_at_start - mrr_at_end) AS contraction_amount
FROM state_change
WHERE mrr_at_end < mrr_at_start AND mrr_at_end > 0
GROUP BY contraction_type
ORDER BY contraction_amount DESC;Plan downgrades обычно — «customer не получает value за price». Seat reduction — «team меньше, чем планировали».
Net MRR movement
Объединить с churn, expansion, new business:
WITH movement AS (
SELECT 'new' AS type, SUM(start_mrr) AS amount FROM new_subscriptions WHERE month = '2026-04'
UNION ALL
SELECT 'expansion', SUM(end_mrr - start_mrr) FROM both WHERE end_mrr > start_mrr
UNION ALL
SELECT 'contraction', -SUM(start_mrr - end_mrr) FROM both WHERE end_mrr < start_mrr AND end_mrr > 0
UNION ALL
SELECT 'churn', -SUM(start_mrr) FROM churned_in_period
)
SELECT
type,
amount,
SUM(amount) OVER () AS net_new_mrr
FROM movement;Частые ошибки
Ошибка 1. Считать contraction = churn. Customer всё ещё платит, просто меньше. Это не churn — это сигнал «недостаточно value».
Ошибка 2. Игнорировать pricing changes. Если вы снизили цены, MRR упал у всех — это не contraction, а pricing event.
Ошибка 3. Не отделять voluntary от involuntary. Payment failed → MRR упал на месяц → восстановилось. Это involuntary, не contraction.
Ошибка 4. Усреднять без cohort'а. SMB vs Enterprise contraction разный. Сегментируйте.
Ошибка 5. Контролировать contraction процентом, не абсолютом. 1 enterprise customer теряет 50% MRR — это критично. 100 SMB по 10% — терпимо. Считайте оба измерения.
Связанные темы
- Как посчитать expansion MRR в SQL
- Как посчитать MRR churn в SQL
- Как посчитать downgrade rate в SQL
- Как посчитать gross dollar retention в SQL
FAQ
Contraction норма?
5-15% от start MRR за год для SMB. Enterprise — < 5%.
Контракция считается в churn rate?
В revenue churn — да. В logo churn — нет (customer не ушёл).
Как чинить?
Customer interviews — узнавать, что не оправдало expectations. Часто — overscoping (продали Premium тому, кому хватит Basic).
Contraction после введения cheaper plan?
Естественно: customers рассчитают, что подходит. Анализируйте net effect.
Можно ли остановить?
Контракционный customer — кандидат на customer success outreach: «как сделать так, чтобы Premium снова имел смысл».