Раздел 42 · Аналитика данных с нуля

Ловушки данных: разбираем чужие готовые ответы

middle~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Бран · продюсер «Хроник Пограничья»

Ваш стажёр прислал, что 21 июня у нас был рекорд: 267 игроков за день. Если правда, повторяем тот ивент каждую неделю. Подтвердите?

В прошлом уроке мы решали вопрос с нуля и знали, где искать болячки. Чаще бывает иначе: цифра уже посчитана, её прислал коллега, и выглядит она правдоподобно. Сегодня разберём три таких «готовых ответа». В каждом сидит одна из классических ловушек данных.

Пять ловушек

Ловушки повторяются из базы в базу. Мы встречали каждую по отдельности, теперь соберём их в один список:

ЛовушкаКак выглядитГде встречали
Дубли событийодно действие оставляет несколько строкповторные вебхуки, размножение строк при JOIN
Тестовые аккаунтысотрудники студии покупают и играютчистка строк
Ботыаккаунты играют по 24 часаDAU и липкость
Часовые поясавремя в UTC сравнивают с местнымпояса
Ошибка выжившегосчитают только тех, кто осталсякогорты

Ошибка выжившего самая коварная из пяти: запрос в ней написан без ошибок, ошибка в выборке.

Ответ первый: рекорд 21 июня

Стажёр написал так:

SELECT started_at::date AS day, count(*) AS dau
FROM sessions
WHERE started_at >= '2026-06-01' AND started_at < '2026-07-01'
GROUP BY day
ORDER BY dau DESC
LIMIT 1;

count(*) считает строки sessions, а у живого игрока в день бывает две-три сессии. Это ловушка дублей событий: одно «пришёл поиграть» оставляет несколько строк. Правильно считать разных игроков и убрать ботов и тестировщиков. Ботов узнаём по сессиям длиннее 20 часов, как в уроке про DAU:

WITH fake AS (
  SELECT id FROM players WHERE email LIKE '%@studio.dev'
  UNION
  SELECT player_id FROM sessions WHERE ended_at - started_at > interval '20 hours'
)
SELECT started_at::date AS day,
       count(*) AS sessions,
       count(DISTINCT player_id) AS players,
       count(DISTINCT player_id) FILTER (WHERE player_id NOT IN (SELECT id FROM fake)) AS dau_clean
FROM sessions
WHERE started_at >= '2026-06-01' AND started_at < '2026-07-01'
GROUP BY day
ORDER BY dau_clean DESC
LIMIT 3;
    day     | sessions | players | dau_clean
------------+----------+---------+-----------
 2026-06-21 |      267 |     169 |       164
 2026-06-20 |      264 |     169 |       163
 2026-06-27 |      255 |     164 |       161

21 июня действительно самый людный день месяца, но людей было 164, а не 267. И это не рекорд ивента: на втором месте 20 июня, на третьем 27-е. Все три дня выходные.

урок из курса

Урок из курса «Аналитика данных с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.