SQLстатистикаперцентилиметрикианалитик данныхPostgreSQLClickHouse

Медиана и перцентили vs среднее: когда что в SQL

2026-06-09 8 мин

Коротко: среднее (avg) хорошо описывает данные только тогда, когда распределение симметрично и без выбросов. Как только в данных есть длинный хвост — латентность ответа сервера, доход на пользователя, время доставки — среднее завышается несколькими большими значениями и перестаёт отражать «типичного» пользователя. В таких случаях берут медиану (p50) и перцентили (p90, p95, p99). В PostgreSQL их считают через PERCENTILE_CONT, в ClickHouse — через quantile. Это один из самых частых вопросов на собеседовании аналитика: «почему по latency смотрят p95, а не среднее».


Чем медиана отличается от среднего

Среднее (mean, avg) — это сумма всех значений, делённая на их количество. Медиана — это значение, которое делит упорядоченный ряд ровно пополам: половина наблюдений меньше неё, половина больше.

Простой пример. Зарплаты в команде из 5 человек: 80, 90, 100, 110 и 1500 тыс. ₽ (последний — основатель).

МетрикаЗначениеЧто говорит
Среднее(80+90+100+110+1500)/5 = 376«Средняя зарплата 376 тыс.» — но столько не получает почти никто
Медиана100Типичный сотрудник получает около 100 тыс.

Среднее в 376 — формально верное, но вводящее в заблуждение число. Медиана 100 описывает реальность.


Что такое перцентиль и как его читать

Перцентиль (квантиль) p — это значение, ниже которого лежит p процентов наблюдений. Медиана — это просто 50-й перцентиль (p50).

Перцентили читают так: «p95 latency = 800 мс» означает, что 95% запросов отрабатывают быстрее 800 мс, а 5% — медленнее. Это honест­нее, чем среднее: оно может быть 150 мс, пока 5% пользователей ждут по 3 секунды и уходят.


Почему по latency смотрят p95 и p99, а не среднее

Время ответа сервера почти всегда имеет правый хвост: большинство запросов быстрые, но есть редкие медленные (холодный кеш, блокировка БД, GC-пауза). Среднее эти медленные запросы «размазывает» и прячет.

Допустим, 1000 запросов: 950 по 100 мс и 50 по 2000 мс.

SLA и алерты строят на p95/p99 именно потому, что они описывают опыт худших пользователей, а не «бумажное» среднее. Если у тебя 1 млн запросов в день, p99 — это 10 000 человек, которые столкнулись с тормозами. Их нельзя игнорировать.

Правило для собеседования: для метрик с хвостом (latency, доход, время) — медиана и высокие перцентили; среднее оставляем для симметричных метрик без выбросов.


Как считать медиану и перцентили в PostgreSQL

В PostgreSQL есть две функции упорядоченного агрегата: PERCENTILE_CONT и PERCENTILE_DISC. Обе вызываются через синтаксис WITHIN GROUP (ORDER BY ...).

SELECT
  percentile_cont(0.5)  WITHIN GROUP (ORDER BY response_ms) AS p50,
  percentile_cont(0.95) WITHIN GROUP (ORDER BY response_ms) AS p95,
  percentile_cont(0.99) WITHIN GROUP (ORDER BY response_ms) AS p99,
  avg(response_ms)                                          AS mean
FROM requests
WHERE created_at >= now() - interval '1 day';

Здесь:

PERCENTILE_CONT vs PERCENTILE_DISC

В 90% задач аналитика берут PERCENTILE_CONT. Запомни это разделение — его любят спрашивать на собесе.

Перцентили по группам

PERCENTILE_CONT — это агрегат, поэтому он отлично работает с GROUP BY:
SELECT
  endpoint,
  percentile_cont(0.95) WITHIN GROUP (ORDER BY response_ms) AS p95_ms,
  count(*) AS requests
FROM requests
GROUP BY endpoint
ORDER BY p95_ms DESC;

Так находят самые медленные эндпоинты по p95, а не по обманчивому среднему.


Как считать перцентили в ClickHouse

В ClickHouse синтаксис другой — функции семейства quantile. Аргумент — доля, колонка передаётся как параметр функции.

SELECT
  quantile(0.5)(response_ms)  AS p50,
  quantile(0.95)(response_ms) AS p95,
  quantile(0.99)(response_ms) AS p99,
  avg(response_ms)            AS mean
FROM requests
WHERE created_at >= now() - INTERVAL 1 DAY;

Ключевые отличия и нюансы ClickHouse:

-- несколько перцентилей одним проходом
SELECT
  endpoint,
  quantiles(0.5, 0.95, 0.99)(response_ms) AS p_array
FROM requests
GROUP BY endpoint;

Важно: ClickHouse quantile по умолчанию приближённый, а PostgreSQL PERCENTILE_CONTточный с интерполяцией. На собесе про ClickHouse уточни, нужна ли точность — тогда quantileExact.


Сравнение синтаксиса: PostgreSQL vs ClickHouse vs другие СУБД

СУБДМедиана / перцентильТип
PostgreSQLpercentile_cont(0.95) WITHIN GROUP (ORDER BY x)Точный, интерполяция
PostgreSQLpercentile_disc(0.95) WITHIN GROUP (ORDER BY x)Точный, без интерполяции
ClickHousequantile(0.95)(x)Приближённый
ClickHousequantileExact(0.95)(x)Точный
MySQL 8+оконкой ROW_NUMBER + ручной расчёт или PERCENT_RANK()нет нативной функции
BigQueryAPPROX_QUANTILES(x, 100)[OFFSET(95)]Приближённый
Snowflakepercentile_cont(0.95) WITHIN GROUP (ORDER BY x)Точный

MySQL до сих пор не имеет встроенной функции перцентиля — там считают через оконные функции, например с NTILE или PERCENT_RANK(). Это тоже частый вопрос: «как посчитать медиану в SQL без percentile-функции».


Как посчитать медиану без percentile-функции (через оконные функции)

Если СУБД не поддерживает PERCENTILE_CONT, медиану берут через ранжирование. Идея: пронумеровать строки по возрастанию и взять центральную (или среднее двух центральных при чётном количестве).

WITH ranked AS (
  SELECT
    response_ms,
    ROW_NUMBER() OVER (ORDER BY response_ms) AS rn,
    COUNT(*)    OVER ()                      AS total
  FROM requests
)
SELECT AVG(response_ms) AS median
FROM ranked
WHERE rn IN (FLOOR((total + 1) / 2.0), CEIL((total + 1) / 2.0));

Этот приём — ROW_NUMBER() OVER (ORDER BY ...) плюс выбор центральной позиции — стоит уметь писать с нуля. Разобраться с оконными функциями глубже можно в SQL-тренажёре, там десятки задач на ROW_NUMBER, RANK и квантили с автопроверкой.


Когда брать среднее, а когда медиану: чек-лист

Используй среднее (avg), когда:

Используй медиану / перцентили, когда:

Дополнительный сигнал: если среднее заметно больше медианы — распределение скошено вправо, выбросы есть, и среднее обманывает. Если они близки — распределение симметрично, можно брать любое.


Частые ошибки с перцентилями


Где потренироваться

Перцентили, медиана и выбор метрики против выбросов — обязательная тема собеседования аналитика и дата-инженера. Разбери её на практике:

Потренируйся бесплатно: 5 SQL-задач без регистрации и курс «SQL с нуля». Перцентили в реальных запросах закрепляются быстрее, чем в теории.

Считай перцентили на практике
SQL-тренажёр с PERCENTILE_CONT и агрегатами. Автопроверка, настоящий PostgreSQL.
Открыть SQL-тренажёр →