Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 09.08 · 25 мин
Продвинутый
neighborrunningDifferencerunningAccumulateDeprecated FunctionsWindow FunctionsLAGLEADallow_deprecated_functions

Устаревшие функции: neighbor, runningDifference, runningAccumulate

Три функции ClickHouse — neighbor(), runningDifference() и runningAccumulate() — были объявлены устаревшими (deprecated) начиная с версии 24.8. В ClickHouse 26.3 LTS их вызов без специального разрешения приводит к ошибке. Этот урок объясняет, почему функции были deprecated, как включить их для чтения legacy-кода и — главное — какие оконные функции использовать вместо них.


Почему эти функции deprecated

Deprecated-функции и их замены на оконные функции
neighbor(col, offset)neighbor(column, offset) -- доступ к значению из соседней строки. Deprecated: результат зависит от физического порядка данных в block, а не от ORDER BY. При параллельном чтении порядок block непредсказуем.
runningDifference(col)runningDifference(column) -- разница текущего значения с предыдущим в block. Deprecated: первая строка каждого block даёт разницу с нулём (а не с предыдущим block). При параллельном чтении block-границы непредсказуемы.
runningAccumulate(state)runningAccumulate(state_col) -- нарастающая агрегация по block. Deprecated: аккумулятор сбрасывается на границе block. При параллельном чтении результат недетерминирован.
LAG / LEADLAG(col, offset, default) OVER (ORDER BY ...) -- детерминированный доступ к предыдущей строке. ORDER BY гарантирует порядок. PARTITION BY разделяет окна. Работает корректно при параллельном чтении.
col - LAG(col)col - LAG(col, 1) OVER (ORDER BY ...) -- разница с предыдущим значением. ORDER BY гарантирует корректный порядок. Нет проблемы block-границ: оконная функция видит всё окно целиком.
SUM() OVER()SUM(col) OVER (ORDER BY ... ROWS UNBOUNDED PRECEDING) -- нарастающая сумма. Работает по всему окну, не сбрасывается на block-границах. Поддерживает PARTITION BY для группировки.

Три ключевые причины deprecation:

  1. Зависимость от block-порядка. Эти функции оперируют строками внутри одного block (до 65 536 строк). Порядок строк в block определяется физическим расположением данных, а не ORDER BY запроса. При параллельном чтении (max_threads > 1) разные потоки обрабатывают разные block, и результат становится недетерминированным.

  2. Сброс на границе block. runningDifference() вычисляет разницу с предыдущей строкой, но первая строка каждого block даёт разницу с нулём. runningAccumulate() сбрасывает аккумулятор на каждой границе block. Это означает, что результат зависит от размера block (max_block_size), который может меняться.

  3. Невозможность гарантировать корректность при параллельной обработке. Оконные функции решают все эти проблемы: OVER (ORDER BY ...) гарантирует детерминированный порядок, а вычисление происходит по всему окну, без сброса на block-границах.


Включение deprecated-функций

Для чтения и отладки legacy-кода:

SET allow_deprecated_functions = 1;

-- Теперь deprecated-функции доступны в текущей сессии
SELECT neighbor(value, -1) FROM t;
WARNING

Не используйте deprecated-функции в новом коде. SET allow_deprecated_functions = 1 — только для анализа legacy-запросов и миграции. Во всех новых запросах используйте оконные функции.


neighbor() и замена на LAG/LEAD

neighbor(column, offset) возвращает значение из строки со смещением offset относительно текущей. Положительный offset — следующая строка, отрицательный — предыдущая.

-- DEPRECATED: neighbor
SET allow_deprecated_functions = 1;
SELECT
    ts,
    value,
    neighbor(value, -1) AS prev_value  -- предыдущая строка
FROM metrics
ORDER BY ts;

Замена — LAG/LEAD:

-- СОВРЕМЕННЫЙ ПОДХОД: LAG/LEAD
SELECT
    ts,
    value,
    LAG(value, 1) OVER (ORDER BY ts) AS prev_value,   -- предыдущая
    LEAD(value, 1) OVER (ORDER BY ts) AS next_value    -- следующая
FROM metrics;
Аспектneighbor()LAG/LEAD
Порядок строкФизический (block)Логический (ORDER BY)
ПараллелизмНедетерминированДетерминирован
Дефолтное значение0/пустая строкаNULL (или 3-й аргумент)
PARTITION BYНетДа

runningDifference() и замена на LAG

runningDifference(column) вычисляет разницу текущего значения с предыдущим. Первая строка в block всегда даёт разницу с нулём.

-- DEPRECATED: runningDifference
SET allow_deprecated_functions = 1;
SELECT
    ts,
    value,
    runningDifference(value) AS diff  -- value - prev_value
FROM metrics
ORDER BY ts;

Проблема block-границ:

Block 1: [100, 200, 300]  -> diff: [100, 100, 100]  -- первое 100 = 100 - 0
Block 2: [400, 500]       -> diff: [400, 100]        -- 400 = 400 - 0 (сброс!)
-- Ожидалось: 400 - 300 = 100, но block не видит предыдущий block

Замена — LAG с вычитанием:

-- СОВРЕМЕННЫЙ ПОДХОД: LAG
SELECT
    ts,
    value,
    value - LAG(value, 1) OVER (ORDER BY ts) AS diff
FROM metrics;
-- Первая строка: NULL (нет предыдущей), а не 0
-- Нет проблемы block-границ

runningAccumulate() и замена на SUM() OVER

runningAccumulate(state_column) выполняет нарастающую агрегацию, но сбрасывается на каждой границе block.

-- DEPRECATED: runningAccumulate
SET allow_deprecated_functions = 1;
SELECT
    ts,
    runningAccumulate(sumState(value)) AS running_sum
FROM metrics
ORDER BY ts;

Замена — агрегатные функции с OVER:

-- СОВРЕМЕННЫЙ ПОДХОД: SUM() OVER
SELECT
    ts,
    value,
    SUM(value) OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING) AS running_sum
FROM metrics;

-- С партиционированием по метрике:
SELECT
    metric_name,
    ts,
    value,
    SUM(value) OVER (
        PARTITION BY metric_name
        ORDER BY ts
        ROWS UNBOUNDED PRECEDING
    ) AS metric_running_sum
FROM metrics;

Оконный вариант корректен при любом max_threads и max_block_size.


Полный пример миграции

Типичный legacy-запрос с тремя deprecated-функциями:

-- LEGACY (deprecated, недетерминированный результат):
SET allow_deprecated_functions = 1;
SELECT
    ts,
    value,
    neighbor(value, -1) AS prev_value,
    runningDifference(ts) AS time_gap,
    runningAccumulate(sumState(value)) AS cumulative
FROM metrics
ORDER BY ts;

Модернизированный вариант:

-- MODERN (детерминированный, корректный при параллельном чтении):
SELECT
    ts,
    value,
    LAG(value, 1) OVER (ORDER BY ts) AS prev_value,
    ts - LAG(ts, 1) OVER (ORDER BY ts) AS time_gap,
    SUM(value) OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING) AS cumulative
FROM metrics;
TIP

Оконные функции подробно рассмотрены в уроке 04 этого модуля. Для полного понимания синтаксиса OVER, PARTITION BY, ROWS/RANGE — обратитесь к нему.


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

  1. neighbor(), runningDifference(), runningAccumulate() deprecated с ClickHouse 24.8. В 26.3 LTS требуют SET allow_deprecated_functions = 1.
  2. Причина: зависимость от block-порядка, сброс на block-границах, недетерминированный результат при параллельном чтении.
  3. Замены: neighbor() -> LAG()/LEAD(), runningDifference() -> col - LAG(col), runningAccumulate() -> SUM()/AVG()/etc. OVER().
  4. Оконные функции гарантируют детерминированный результат через ORDER BY в OVER-клаузе. Нет проблемы block-границ.
  5. allow_deprecated_functions = 1 — только для анализа legacy-кода, не для нового кода.

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

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

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

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