Как посчитать crash-free users в SQL
Содержание:
Зачем crash-free
Crash-free users — главная stability метрика mobile. Если 99.5% юзеров не упало приложение, 0.5% — упало хотя бы раз. Industry-стандарт: 99.9% для consumer apps. Падение этой метрики после релиза = критическая регрессия, hotfix.
Формула
crash_free_users = (users_without_crash / total_active_users) × 100В отличие от crash rate (events / total events), crash-free — на уровне юзеров. Один юзер с 10 crash = одна точка отказа.
Crash-free в SQL
WITH active_users AS (
SELECT DISTINCT user_id
FROM app_sessions
WHERE session_date >= CURRENT_DATE - INTERVAL '7 days'
),
crashed_users AS (
SELECT DISTINCT user_id
FROM crash_events
WHERE crash_date >= CURRENT_DATE - INTERVAL '7 days'
)
SELECT
(SELECT COUNT(*) FROM active_users) AS active,
(SELECT COUNT(*) FROM crashed_users) AS crashed,
(1 - (SELECT COUNT(*) FROM crashed_users)::NUMERIC / NULLIF((SELECT COUNT(*) FROM active_users), 0)) * 100 AS crash_free_pct;99.5%+ — хорошо. 99% — есть проблема. < 98% — большая часть юзеров видят crash.
По версии
После релиза мониторят на конкретной версии:
WITH crashed AS (
SELECT DISTINCT user_id
FROM crash_events
WHERE crash_date >= CURRENT_DATE - INTERVAL '7 days'
)
SELECT
s.app_version,
s.platform,
COUNT(DISTINCT s.user_id) AS active_users,
COUNT(DISTINCT s.user_id) FILTER (WHERE c.user_id IS NOT NULL) AS crashed_users,
(1 - COUNT(DISTINCT s.user_id) FILTER (WHERE c.user_id IS NOT NULL)::NUMERIC
/ NULLIF(COUNT(DISTINCT s.user_id), 0)) * 100 AS crash_free_pct
FROM app_sessions s
LEFT JOIN crashed c USING (user_id)
WHERE s.session_date >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY s.app_version, s.platform
ORDER BY s.app_version DESC, s.platform;Падение CF от 99.9% (старая версия) до 98% (новая) — сигнал отката релиза.
Regression detection
WITH version_stats AS (
SELECT
app_version,
platform,
DATE_TRUNC('day', session_date)::DATE AS day,
ROUND((1 - COUNT(DISTINCT user_id) FILTER (WHERE crashed)::NUMERIC
/ NULLIF(COUNT(DISTINCT user_id), 0)) * 100, 3) AS crash_free_pct
FROM session_with_crash_flag
WHERE session_date >= CURRENT_DATE - INTERVAL '14 days'
GROUP BY app_version, platform, DATE_TRUNC('day', session_date)
)
SELECT
app_version,
platform,
AVG(crash_free_pct) FILTER (WHERE day >= CURRENT_DATE - INTERVAL '3 days') AS recent_cf,
AVG(crash_free_pct) FILTER (WHERE day < CURRENT_DATE - INTERVAL '3 days') AS baseline_cf,
AVG(crash_free_pct) FILTER (WHERE day >= CURRENT_DATE - INTERVAL '3 days') -
AVG(crash_free_pct) FILTER (WHERE day < CURRENT_DATE - INTERVAL '3 days') AS delta_pp
FROM version_stats
GROUP BY app_version, platform
HAVING ABS(
AVG(crash_free_pct) FILTER (WHERE day >= CURRENT_DATE - INTERVAL '3 days') -
AVG(crash_free_pct) FILTER (WHERE day < CURRENT_DATE - INTERVAL '3 days')
) > 0.5
ORDER BY delta_pp;Версии с регрессией > 0.5pp — кандидаты на откат.
Частые ошибки
Ошибка 1. Crash rate вместо crash-free. Crash rate = events / events. Не учитывает многократные crashes у одного юзера.
Ошибка 2. Считать на all-time. Свежий релиз с CF 99% выглядит OK, если усреднить с двухнедельной историей. Считайте per day.
Ошибка 3. Игнорировать ANRs (Application Not Responding) на Android. ANR — не crash, но user experience такой же. Включайте в knowledge base.
Ошибка 4. Один CF на платформу. iOS vs Android имеют разную CF. Также OS version имеет значение (iOS 18 vs 17).
Ошибка 5. Не сегментировать на crash type. Native crash vs JS crash (для RN/Flutter) — разные fixing strategies.
Связанные темы
- Как посчитать crash rate в SQL
- Как посчитать app startup time в SQL
- Как посчитать error rate в SQL
- Как посчитать data quality score в SQL
FAQ
Какой CF хороший?
Consumer apps: 99.9%+. Games: 99.5%+. Enterprise: 99.95%.
CF включает background crashes?
По вкусу. Foreground важнее (юзер видит). Background = ANR.
Crash-free sessions vs users?
User — строже (один user с many crashes считается раз). Session — больше total volume.
Когда rollback?
CF падение > 1pp или абсолютно < 99% — стоит откатываться.
Тулинг?
Crashlytics, Bugsnag — стандарт. В SQL — для собственных пайплайнов.