Learning Platform
Глоссарий Troubleshooting
Урок 09.09 · 35 мин
Продвинутый
uniquniqCombineduniqExactuniqHLL12uniqThetaquantilequantileTDigestquantileExactquantileTimingquantileBFloat16Approximate FunctionsHyperLogLog

Приближенные функции: uniq и quantile семейства

ClickHouse предоставляет два семейства приближенных функций: uniq (оценка кардинальности — сколько уникальных значений) и quantile (оценка перцентилей — какое значение на позиции N%). Приближенные функции жертвуют абсолютной точностью ради радикального снижения потребления памяти и времени вычисления. На миллиардах строк разница между точным и приближенным результатом — секунды vs минуты, мегабайты vs гигабайты.


Семейство uniq: оценка кардинальности

Семейство uniq: 6 функций для подсчёта уникальных значений
uniq -- адаптивныйuniq(col) -- адаптивный алгоритм (HyperLogLog + sampling). Погрешность ~1-2%. Малый расход памяти. Рекомендация: дефолтный выбор для аналитики, где допустима 2% погрешность.
uniqCombined -- гибридuniqCombined(col) -- гибридный алгоритм (Array + Hash + HLL12). Погрешность ~1%. Средний расход памяти. Рекомендация: когда нужен -State/-Merge для MV/AggregatingMergeTree.
uniqHLL12 -- 2.5 КБuniqHLL12(col) -- HyperLogLog с 12-bit регистрами. Погрешность ~1.5%. Фиксированный размер состояния ~2.5 КБ. Рекомендация: когда нужен предсказуемый размер состояния.
uniqCombined64 -- 64-bituniqCombined64(col) -- как uniqCombined, но с 64-bit hash. Погрешность ~1%. Рекомендация: для высокой кардинальности (более 100M уникальных значений), где 32-bit hash даёт коллизии.
uniqExact -- точныйuniqExact(col) -- полный hash set. Погрешность 0% (точный). Память: пропорциональна кардинальности (неограниченна). Рекомендация: только когда бизнес требует абсолютно точный подсчёт.
uniqTheta -- set opsuniqTheta(col) -- Theta Sketch. Погрешность ~1%. Уникальная возможность: поддержка set-операций (union, intersect, not). Рекомендация: когда нужны пересечения/объединения множеств уникальных значений.

Сравнительная таблица

ФункцияАлгоритмПогрешностьПамятьКогда использовать
uniqАдаптивный (HLL)~1-2%МалаяДефолтный выбор для аналитических дашбордов
uniqCombinedArray+Hash+HLL12~1%СредняяНужен -State/-Merge для MV
uniqCombined64Array+Hash+HLL12 (64-bit)~1%СредняяКардинальность более 100M
uniqHLL12HyperLogLog 12-bit~1.5%2.5 КБПредсказуемый размер состояния
uniqExactПолный hash set0%НеограниченнаяТочный подсчёт обязателен
uniqThetaTheta Sketch~1%МалаяSet-операции (intersect/union)

Примеры использования

-- Дефолтный выбор: приближенный подсчёт уникальных пользователей
SELECT
    toDate(event_time) AS day,
    uniq(user_id) AS unique_users
FROM events
GROUP BY day
ORDER BY day;
-- Быстро, ~1-2% погрешность, минимум памяти
-- Точный подсчёт: когда бизнес требует абсолютной точности
-- (AB-тестирование, биллинг, compliance-отчёты)
SELECT
    experiment_id,
    variant,
    uniqExact(user_id) AS exact_users
FROM ab_test_events
GROUP BY experiment_id, variant;
-- Медленнее, RAM пропорциональна кардинальности
-- Set-операции: пересечение сегментов через uniqTheta
SELECT
    uniqTheta(user_id) AS segment_a_users
FROM events WHERE segment = 'premium';

-- Пересечение: пользователи И premium, И active
SELECT uniqThetaIntersect(sketch_a, sketch_b)
FROM (
    SELECT
        uniqThetaState(user_id) AS sketch_a
    FROM events WHERE segment = 'premium'
) a, (
    SELECT
        uniqThetaState(user_id) AS sketch_b
    FROM events WHERE segment = 'active'
) b;

Семейство quantile: оценка перцентилей

Перцентили — ключевой инструмент для анализа распределений: P50 (медиана), P95 (95-й перцентиль), P99 (99-й перцентиль).

Сравнительная таблица

ФункцияАлгоритмСкоростьТочностьОграничения
quantileReservoir samplingБыстраяПриближеннаяНедетерминированная
quantileTDigestT-DigestСредняяХорошая (~1%)
quantileExactПолная сортировкаМедленнаяТочнаяRAM = все значения
quantileTimingФиксированные бакетыОчень быстраяХорошаяМаксимум 30 000 (30 секунд)
quantileDeterministicДетерминированный samplingБыстраяПриближеннаяРезультат повторяемый
quantileBFloat16BFloat16 квантизацияОчень быстраяНизкаяДля быстрой оценки

quantile — дефолтный выбор

-- P50 (медиана), P95, P99 для латентности запросов
SELECT
    quantile(0.5)(query_duration_ms) AS p50,
    quantile(0.95)(query_duration_ms) AS p95,
    quantile(0.99)(query_duration_ms) AS p99
FROM system.query_log
WHERE type = 'QueryFinish';

Результат недетерминированный — при повторном запросе может незначительно отличаться (reservoir sampling использует случайную выборку).


quantileTDigest — баланс скорости и точности

-- P99 латентности API по эндпоинтам
SELECT
    endpoint,
    quantileTDigest(0.99)(latency_ms) AS p99_latency
FROM api_logs
GROUP BY endpoint
ORDER BY p99_latency DESC
LIMIT 10;

T-Digest обеспечивает ~1% относительную погрешность для крайних перцентилей (P95, P99) и лучшую точность для медианы. Состояние фиксированного размера — не зависит от количества данных.


quantileTiming — для латентностей

-- Очень быстрый P99 для сетевых латентностей
SELECT
    service,
    quantileTiming(0.99)(response_time_ms) AS p99
FROM requests
GROUP BY service;
WARNING

quantileTiming принимает значения от 0 до 30 000 (интерпретируемые как миллисекунды, максимум 30 секунд). Значения больше 30 000 приравниваются к 30 000. Если ваши данные могут превышать 30 секунд, используйте quantileTDigest.


quantileExact — абсолютная точность

-- Точная медиана зарплат (финансовые отчёты)
SELECT
    department,
    quantileExact(0.5)(salary) AS median_salary
FROM employees
GROUP BY department;
-- Хранит все значения в памяти, затем сортирует

Использовать только когда бизнес-требования запрещают приближение (финансы, compliance). На миллиардах строк потребление памяти может быть значительным.


Фреймворк выбора функции

Выбор uniq-функции

  1. Нужна точность 0%? -> uniqExact (проверьте RAM-бюджет)
  2. Нужны set-операции (intersect/union)? -> uniqTheta
  3. Кардинальность более 100M? -> uniqCombined64
  4. Нужен -State/-Merge для MV? -> uniqCombined
  5. Нужен фиксированный размер состояния? -> uniqHLL12
  6. Все остальные случаи -> uniq (дефолт)

Выбор quantile-функции

  1. Нужна точность 100%? -> quantileExact
  2. Данные — латентности до 30 секунд? -> quantileTiming (самая быстрая)
  3. Нужна точность на хвостах (P95/P99)? -> quantileTDigest
  4. Нужен детерминированный результат? -> quantileDeterministic
  5. Все остальные случаи -> quantile (дефолт)

Множественные перцентили за один проход

ClickHouse поддерживает вычисление нескольких перцентилей одним вызовом функции:

-- Вместо 3 отдельных quantile():
SELECT
    quantiles(0.5, 0.95, 0.99)(latency_ms) AS percentiles
FROM requests;
-- Возвращает Array: [p50, p95, p99]

-- Аналогично для T-Digest:
SELECT
    quantilesTDigest(0.5, 0.95, 0.99)(latency_ms) AS percentiles
FROM requests;

Это эффективнее, чем три отдельных вызова — данные проходятся один раз.


Комбинаторы с приближенными функциями

Все uniq- и quantile-функции поддерживают комбинаторы из урока 01:

-- uniqIf: подсчёт уникальных только среди платящих
SELECT uniqIf(user_id, plan = 'paid') AS paying_users
FROM users;

-- quantileTDigestIf: P99 только для ошибок
SELECT quantileTDigestIf(0.99)(latency_ms, status_code >= 500) AS error_p99
FROM api_logs;

-- uniqState/uniqMerge: для MV + AggregatingMergeTree
-- (подробнее в уроке 01 о комбинаторах)

Ключевые выводы

  1. uniq — дефолтный выбор для подсчёта уникальных значений (~1-2% погрешность, минимум памяти). uniqExact — только когда бизнес требует точности.
  2. uniqTheta — единственный вариант, поддерживающий set-операции (intersect/union) на sketch-уровне.
  3. quantileTDigest — лучший баланс точности и скорости для P95/P99. quantileTiming — самая быстрая, но ограничена 30 секундами.
  4. quantiles()/quantilesTDigest() — множественные перцентили за один проход данных.
  5. Фреймворк выбора: точность -> ограничения -> память -> скорость. Начинайте с приближенной функции, переходите к точной только по требованию бизнеса.
BtrBlocks: каскадное кодирование с вероятностными структурами Streaming: event time, watermarks, windows

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Биллинговая система должна подсчитать точное количество уникальных рекламных показов для выставления счёта клиенту. Погрешность недопустима. Какую функцию использовать?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 10