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 с нуля». Перцентили в реальных запросах закрепляются быстрее, чем в теории.

Частые вопросы

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

Среднее — это сумма всех значений, делённая на их количество, поэтому оно учитывает величину каждого значения и один большой выброс тянет его вверх. Медиана делит упорядоченный ряд ровно пополам и учитывает только порядок — выброс сдвигает её максимум на одну позицию. Пример: зарплаты 80, 90, 100, 110 и 1500 тыс. дают среднее 376 тыс., которое почти никто не получает, а медиана 100 тыс. описывает типичного сотрудника.

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

Время ответа сервера почти всегда имеет правый хвост: большинство запросов быстрые, но есть редкие медленные, и среднее их «размазывает» и прячет. Например, при 950 запросах по 100 мс и 50 по 2000 мс среднее будет 195 мс и выглядит отлично, а p95 — около 2000 мс, то есть каждый 20-й пользователь ждёт две секунды. SLA и алерты строят на p95/p99, потому что они описывают опыт худших пользователей, а не «бумажное» среднее.

Как посчитать медиану и перцентили в SQL (PostgreSQL и ClickHouse)?

В PostgreSQL используют percentile_cont(0.5) WITHIN GROUP (ORDER BY column) — аргумент задаёт долю (0.5 — медиана, 0.95 — p95), функция работает как агрегат и сочетается с GROUP BY. В ClickHouse синтаксис другой: quantile(0.95)(column), есть точный вариант quantileExact и quantiles(0.5, 0.95, 0.99)(column) для нескольких перцентилей одним проходом. Важно: quantile в ClickHouse по умолчанию приближённый, а PERCENTILE_CONT в PostgreSQL — точный с интерполяцией.

В чём разница между PERCENTILE_CONT и PERCENTILE_DISC?

PERCENTILE_CONT интерполирует между двумя соседними значениями: для p50 из чисел 10 и 20 вернёт 15 — подходит для непрерывных метрик вроде времени и денег. PERCENTILE_DISC возвращает реальное значение из набора без интерполяции: для тех же чисел вернёт 10 — подходит, когда нужно именно существующее значение, например ID или категория. В 90% задач аналитика берут PERCENTILE_CONT.

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

Самые частые: считают среднее по тяжёлохвостой метрике (latency, ARPU), хотя нужны p50/p95; усредняют перцентили — нельзя брать «среднее p95 по дням», перцентили не аддитивны, нужно пересчитывать по всему пулу данных за период. Также путают PERCENTILE_CONT и PERCENTILE_DISC, забывают, что дефолтный quantile в ClickHouse приближённый, и сравнивают p95 на выборках разного размера, где высокий перцентиль нестабилен.

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