Skip to main content

Обратно несовместимые изменения

Изменения в запросах, функциях и синтаксисе

  • Для представлений, тело которых представляет собой простой SELECT над одной таблицей Distributed, весь внешний запрос теперь передаётся на сегменты (новая настройка optimize_trivial_view_pushdown_to_distributed, включена по умолчанию). Это изменяет наблюдаемое поведение таких представлений: FINAL и SAMPLE, указанные при обращении к представлению, теперь передаются в локальную таблицу сегмента, а не игнорируются, а extremes не возвращается в кластерах из одного сегмента. Чтобы вернуть прежнее поведение, установите optimize_trivial_view_pushdown_to_distributed = 0. #101791 (simonmichal).
  • Патч-части облегчённых UPDATE теперь хранятся на диске в новом формате v2: они отсортированы по (sorting_key..., _block_number, _block_offset) и применяются с помощью нового алгоритма слияния. Пиковое потребление памяти ограничено размером наибольшей последовательности строк с одинаковым ключом сортировки, а не всего патча, а обновления, пересекающие границы слияний, больше не переключаются на применение через Join в памяти. Патч-части в старом формате по-прежнему доступны для чтения. При поэтапном обновлении с версии ниже 26.8 сохраняйте patch_parts_version = 'v1' или используйте настройку compatibility, пока все реплики не будут обновлены. #103182 (CurtizJ).
  • AggregatingMergeTree теперь при создании таблицы отклоняет схемы, в которых столбец не входит ни в ключ сортировки, ни в число мер с состоянием агрегации (AggregateFunction/SimpleAggregateFunction). При фоновых слияниях такие столбцы незаметно сводятся к произвольному значению, из-за чего запросы с GROUP BY или фильтрацией по ним возвращают неверные результаты. Чтобы вернуть прежнее поведение, установите allow_dimensions_outside_sorting_key = 1. #108087 (alexey-milovidov).
  • ClickHouse теперь всегда использует единый хеш дедупликации вставок как для синхронных, так и для асинхронных вставок; устаревшие варианты дедупликации для отдельных вставок удалены. Серверная настройка insert_deduplication_version сохранена в качестве защиты при миграции: сервер не запустится, если ей присвоено устаревшее значение (old_separate_hashes или compatible_double_hashes). Чтобы обновиться с версии, использовавшей устаревшее значение, сначала запустите релиз с поддержкой compatible_double_hashes (он записывает как устаревшие, так и единые хеши). Для реплицируемых таблиц держите его запущенным не менее replicated_deduplication_window_seconds (по умолчанию один час; окна по умолчанию хранят единые хеши всех вставок за этот период, чего считается достаточно для цикла повторных попыток вставки). Для нереплицируемых таблиц с non_replicated_deduplication_window > 0 это окно определяется количеством вставок, а не временем, поэтому используйте compatible_double_hashes как минимум на протяжении такого же числа вставок. Затем, перед обновлением до этой версии, удалите настройку (или установите для неё значение new_unified_hash). #108361 (CheSema).
  • Настройка use_legacy_to_time теперь по умолчанию равна 0, поэтому toTime преобразует значения в тип данных Time, а не приводит дату со временем к фиксированной дате. Прежнее поведение по-прежнему доступно через функцию toTimeWithFixedDate или при установке use_legacy_to_time = 1. #108729 (alexey-milovidov).
  • Модели наивного байесовского классификатора (используемые naiveBayesClassifier) теперь настраиваются как словарь с макетом NAIVE_BAYES, который строится при загрузке из таблицы предварительно агрегированных частот n-грамм по классам. Прежняя конфигурация на стороне сервера (конфигурационный XML-файл со ссылками на сериализованные файлы моделей .bin) больше не поддерживается — существующие модели необходимо пересоздать в виде словарей. Наряду с naiveBayesClassifier добавлены три новые функции: naiveBayesClassifierWithProb возвращает предсказанный класс вместе с его вероятностью, naiveBayesClassifierWithAllProbs возвращает все классы с их вероятностями, а naiveBayesNgrams разбивает текст на n-граммы так же, как это делает словарь, что позволяет формировать обучающие данные из необработанного размеченного текста. Кроме того, применён ряд оптимизаций производительности: на языковой модели триграмм кодовых точек размером 9,7 МиБ потребление памяти снизилось примерно в 49 раз (с 1,84 ГиБ до 38 МиБ), а загрузка и классификация ускорились примерно в 11 раз. #108773 (nihalzp).
  • Значение по умолчанию настройки max_insert_threads изменено с 1 (без параллелизма) на auto, что соответствует числу ядер CPU, доступных серверу (при нехватке памяти оно уменьшается с учётом max_insert_threads_min_free_memory_per_thread). Благодаря этому INSERT SELECT по умолчанию выполняется параллельно; кроме того, при подходящем обычном INSERT может распараллеливаться и запись, если путь записи в целевую таблицу допускает безопасное разветвление. Это может изменить количество создаваемых кусков и порядок вставленных строк. Чтобы вернуть прежнее поведение, установите max_insert_threads в 1 или задайте для compatibility версию ниже 26.8. #109000 (alexey-milovidov). #109006 (alexey-milovidov).
  • При чтении CSV обычный Tuple теперь в любой позиции принимает по одному полю на каждый элемент, поэтому \N в поле элемента верхнего уровня относится именно к этому элементу, и к нему применяется input_format_null_as_default. Ранее начальный \N трактовался как NULL для всего столбца, из-за чего строка заменялась значением столбца по умолчанию, а оставшиеся ячейки элементов затем не удавалось разобрать. Это изменение нарушает обратную совместимость для строк, в которых для всего обычного Tuple указано одно поле: теперь в такой строке не хватает оставшихся элементов, и она отклоняется; а для Tuple из одного элемента, где число полей в обоих случаях одинаково, вместо DEFAULT столбца молча подставляется значение элемента по умолчанию. Чтобы снова читать такое поле как весь столбец, установите input_format_csv_deserialize_separate_columns_into_tuple = 0. #109744 (groeneai).
  • В CREATE USER и ALTER USER добавлена конструкция VALID FOR <interval> как сокращённая форма VALID UNTIL. Срок действия вычисляется в момент выполнения запроса как текущее время плюс заданный интервал и сохраняется в форме VALID UNTIL. Столбец valid_until таблицы system.users теперь имеет тип Array(DateTime64(0)) вместо Array(DateTime), чтобы точно представлять сроки после 2106 года; инструменты, читающие этот столбец, должны поддерживать новый тип. #110171 (alexey-milovidov).
  • EXPLAIN SYNTAX теперь возвращает переформатированный запрос в виде одной записи типа String (со встроенными переводами строк) вместо отдельной записи для каждой строки, поэтому результат представляет собой одну строку, пригодную для непосредственного использования (например, SELECT count() FROM (EXPLAIN SYNTAX ...) возвращает 1). Это поведение управляется новой опцией single_record, которая по умолчанию равна 1; чтобы вернуть прежний вывод по одной записи на строку, установите single_record = 0. Другие виды EXPLAIN (PLAN/PIPELINE/AST) по-прежнему выводят дерево построчно. #110479 (alexey-milovidov).
  • Функция hasColumnInTable больше не принимает необязательные аргументы hostname, username и password для проверки наличия столбца на произвольном удалённом сервере; осталась только форма hasColumnInTable(database, table, column). Удалённый режим убран из соображений безопасности: он позволял любому пользователю инициировать исходящие подключения к произвольным хостам, приводил к утечке учётных данных в журналы запросов и не требовал никакой привилегии. #110881 (alexey-milovidov).
  • Движки баз данных PostgreSQL и MaterializedPostgreSQL теперь учитывают параметр конфигурации сервера remote_url_allow_hosts — так же, как это уже делают табличный движок PostgreSQL, табличная функция postgresql и словари, созданные через DDL. Ограничение применяется при CREATE DATABASE и при выполнении пользователем ATTACH DATABASE: если на сервере настроен remote_url_allow_hosts, попытка создать или подключить базу данных PostgreSQL или MaterializedPostgreSQL, указывающую на хост вне белого списка, теперь завершается ошибкой UNACCEPTABLE_URL. Уже существующие базы данных по-прежнему загружаются при запуске сервера, поэтому после обновления сервер гарантированно сможет запуститься. #111135 (alexey-milovidov).
  • Удалены основанные на библиотеке Apache Arrow считыватель и модуль записи для форматов Arrow и ArrowStream. Нативная реализация ClickHouse, используемая по умолчанию начиная с версии 26.7, теперь единственная. Настройки input_format_arrow_use_native_reader и output_format_arrow_use_native_writer устарели: они по-прежнему принимаются, но ни на что не влияют, поэтому запрос, в котором им присваивалось значение 0 для принудительного использования реализации Apache Arrow, теперь использует нативную реализацию. #111996 (alexey-milovidov).
  • Учётные данные TLS для источника MySQL (ssl_ca, ssl_cert, ssl_key) больше нельзя задавать из SQL в виде путей к файлам — в именованной коллекции, созданной с помощью CREATE NAMED COLLECTION, в качестве аргумента запроса или в запросе CREATE DICTIONARY, — поскольку сервер открывает эти файлы со своими собственными привилегиями. Пути по-прежнему поддерживаются в конфигурационном файле сервера. В остальных случаях передавайте содержимое сертификата или ключа в новых параметрах ssl_ca_pem, ssl_cert_pem и ssl_key_pem, которые маскируются в журналах и в запросах SHOW так же, как пароли. #112070 (alexey-milovidov).
  • disable_insertion_and_mutation теперь запрещает фоновое потребление из таблиц Kafka, RabbitMQ и NATS, но по-прежнему разрешает прямую запись во внешнее хранилище. Для заблокированных таблиц Kafka2, NATS и RabbitMQ потребители не инициализируются при прямом SELECT. Недавно добавленная настройка message_queue_disable_insertion теперь требует перезапуска сервера. #113660 (cwurm).
  • Оконные PARTITION BY и ORDER BY по столбцу типа AggregateFunction теперь отклоняются с ошибкой ILLEGAL_COLUMN — так же, как уже отклонялся ORDER BY верхнего уровня по такому столбцу. Ранее такой запрос принимался как минимум одним анализатором, а оконный PARTITION BY разбивал данные по-разному в зависимости от max_threads. Запрет распространяется и на состояние, вложенное в Array, Tuple, Map, Variant или SimpleAggregateFunction. Изменение не затрагивает SimpleAggregateFunction над обычным типом, QBit, а также GROUP BY и DISTINCT по состоянию. #113878 (groeneai).
  • Исправлены проверки доступа для команд SYSTEM ... CACHE ON CLUSTER. Они требовали группу привилегий SYSTEM DROP CACHE вместо привилегии конкретной команды, из-за чего, с одной стороны, отказывали в доступе пользователям с отдельной детализированной привилегией на кэш, а с другой — позволяли обладателю группы выполнять SYSTEM SYNC FILESYSTEM CACHE ON CLUSTER без привилегии SYSTEM SYNC FILESYSTEM CACHE. #114042 (groeneai).
  • Движок таблицы NATS теперь принимает учётные данные непосредственно в новой настройке nats_credentials (в том же формате, что и содержимое файла .creds) и больше не принимает nats_credential_file из SQL: этот путь указывает на файл в файловой системе сервера, который сервер открывает со своими собственными привилегиями, поэтому его можно задать только в именованной коллекции, определённой в файле конфигурации сервера, либо как nats.credential_file непосредственно в конфигурации сервера. Запрос может заменить такой заданный в конфигурации путь встроенными nats_credentials, если только администратор не зафиксировал его с помощью <nats_credential_file overridable="false">. Таблицы, созданные до введения этого ограничения, продолжат работать после обновления. #114644 (alexey-milovidov).

Изменения типов данных и форматов

  • Формат архивов резервных копий zip/zipx теперь отклоняется для резервных копий, хранящихся в объектном хранилище, — как для прямых пунктов назначения S3(...)/AzureBlobStorage(...), так и для пунктов назначения Disk(...), размещённых в S3 или Azure, — при выполнении как BACKUP, так и RESTORE. Для чтения центрального каталога zip-архива требуется произвольный доступ (seek), который в объектном хранилище выполняется очень медленно. Вместо него используйте формат на основе tar, например tar.gz. #101770 (Onyx2406).
  • Поддерживаемый диапазон DateTime64 расширен с [1900-01-01, 2299-12-31] до [0000-01-01, 9999-12-31]. Значения за пределами прежнего диапазона теперь вычисляются корректно (с помощью cctz), а не усекаются до граничного значения. При точности 8 или 9 диапазон остаётся более узким, поскольку такты хранятся в виде Int64 (при наносекундной точности максимальным значением по-прежнему остаётся 2262-04-11). Обратная совместимость: если ранее вы использовали значения даты и времени вне диапазона, но полагались на весьма специфические правила насыщения внутри старого диапазона, учтите, что теперь результаты будут более корректными. #107907 (alexey-milovidov).
  • Число JSON без кавычек для столбца DateTime64/DateTime в JSONEachRow и аналогичных форматах теперь интерпретируется как Unix-временная метка (секунды с начала эпохи) с необязательной точностью до долей секунды — так же, как в формате Values, CAST и toDateTime64. Ранее число с дробной частью (например, 1703363853.035) отклонялось с ошибкой CANNOT_PARSE_INPUT_ASSERTION_FAILED, а целое число без кавычек (например, 1703363853) считывалось как необработанное масштабированное значение DateTime64, что давало временную метку вида 1970-.... Это обратно несовместимое изменение для целых чисел без кавычек, передаваемых в столбцы DateTime64; строк в кавычках и собственного JSON-вывода ClickHouse (где значения всегда в кавычках) оно не касается. #108091 (alexey-milovidov).
  • Экспериментальный кодек ALP теперь выполняет арифметику масштабирования Float32 в Float64, что устраняет исключения на десятичных данных и значительно повышает коэффициент сжатия. #111627 (rienath).
  • Значения настроек временных интервалов (в миллисекундах/секундах), вызывающие переполнение Int64 при пересчёте в микросекунды, теперь отклоняются #112757 (azat).
  • Асинхронные метрики теперь могут иметь тип данных Map, а метрики для отдельных ядер CPU и устройств объединены в единые метрики типа «ключ-значение»: вместо OSUserTimeCPU0, OSUserTimeCPU1, … теперь используется одна метрика OSUserTimeCPU с отображением номера ядра CPU в значение (аналогично для других метрик OS*TimeCPU*, CPUFrequencyMHz_*, Temperature*, EDAC*, Block*_*, Network(Receive|Send)*_*, Disk*_*, *BlobsQueueEstimate и AsyncLogging*QueueSize). В system.asynchronous_metrics появился новый столбец key_values Map(LowCardinality(String), Float64) (для таких метрик столбец value содержит NaN), system.asynchronous_metric_log записывает их по одной строке на ключ с использованием нового столбца key, конечная точка Prometheus экспортирует их с меткой (например, ClickHouseAsyncMetrics_BlockReadBytes{device="sda"}), а MetricsTransmitter для Graphite отправляет их в виде <prefix>.<Metric>.<key>. Если ваша система мониторинга использует старые имена метрик, установите для asynchronous_metrics_key_values_mode значение legacy_names, чтобы сохранить их, или both на время миграции; эта настройка сервера применяется командой SYSTEM RELOAD CONFIG без перезапуска. #115333 (alexey-milovidov). #116791 (alexey-milovidov).
  • Диски на базе объектного хранилища теперь по умолчанию используют нативные транзакции хранилища метаданных, что повышает согласованность обновлений метаданных. #89658 (Michicosun).

Изменения настроек и конфигурации

  • Удалены давно устаревшие функции snowflakeToDateTime, snowflakeToDateTime64, dateTimeToSnowflake и dateTime64ToSnowflake. Они были объявлены устаревшими ещё в v24.6 в пользу snowflakeIDToDateTime, snowflakeIDToDateTime64, dateTimeToSnowflakeID и dateTime64ToSnowflakeID, которые и следует использовать вместо них. Настройка allow_deprecated_snowflake_conversion_functions (ранее позволявшая снова их включить) теперь считается устаревшей и ни на что не влияет. #108711 (alexey-milovidov).
  • Поддерживаемый диапазон Date32 расширен с [1900-01-01, 2299-12-31] до [0000-01-01, 9999-12-31] и теперь совпадает с диапазоном DateTime64. При разборе и преобразованиях теперь принимается весь расширенный диапазон, а значения больше не обрезаются молча до старых границ. Замечания об обратной совместимости: при числовом преобразовании toDate32(N) значения в диапазоне [120530, 2932896] теперь интерпретируются как номера дней (даты с 2300-01-01 по 9999-12-31), а не как Unix-временные метки начала 1970 года. Это соответствует правилу, согласно которому число, попадающее в диапазон номеров дней, считается номером дня. Числа меньше номера дня 0000-01-01 и временные метки после 9999-12-31 приводятся к новым границам. #111534 (alexey-milovidov).

Прочие обратно несовместимые изменения

  • arrayIntersect и arraySymmetricDifference больше не считают значение, повторяющееся внутри одного аргумента, так, будто оно встречается в нескольких аргументах. Запросы, рассчитанные на прежнее поведение, теперь могут возвращать другие результаты: arrayIntersect([1], [2], [1, 1]) возвращает [] вместо [1], arrayIntersect([1, 2], [2], [1, 1, 2]) возвращает [2] вместо [1, 2], а arraySymmetricDifference([1], [2], [1, 1]) возвращает [2, 1] вместо [2]. Для arraySymmetricDifference достаточно и двух аргументов: arraySymmetricDifference([1], [2, 2]) возвращает [2, 1] вместо [1]. Теперь значение засчитывается для аргумента только в том случае, если оно присутствовало во всех предшествующих аргументах, поэтому результат содержит ровно те значения, которые есть во всех аргументах. В рамках того же изменения arrayIntersect строит хеш-таблицу по наименьшему аргументу, а не по всем сразу, благодаря чему работает до 1,85 раза быстрее и потребляет на треть меньше памяти, если аргументы сильно различаются по размеру. Изменение не затрагивает arrayUnion. #113021 (alexey-milovidov).
  • Тип статистики столбцов minmax объявлен устаревшим. #108680 (hanfei1991).
  • Исправлена проверка прав доступа для SYSTEM PREWARM PRIMARY INDEX CACHE ... ON CLUSTER, которая ошибочно требовала привилегию SYSTEM PREWARM MARK CACHE вместо SYSTEM PREWARM PRIMARY INDEX CACHE. #109198 (Algunenano).
  • Исправлена ошибка, из-за которой SYSTEM STOP/START CLEANUP и SYSTEM STOP/START VIRTUAL PARTS UPDATE ON CLUSTER требовали привилегию SYSTEM PULLING REPLICATION LOG вместо SYSTEM CLEANUP / SYSTEM VIRTUAL PARTS UPDATE. #110289 (groeneai).
  • Глоб-шаблон / (любое количество каталогов) теперь соответствует и самому текущему каталогу. Ранее / в глоб-шаблонах не обрабатывался как особый случай, поэтому data/**/file.txt не соответствовал data/file.txt (нулевой уровень вложенности каталогов). #97676 (alexey-milovidov).

Новые возможности

Функции и типы данных

  • Добавлены функции parseQueryToJSON и formatQueryFromJSON для сериализации и десериализации AST в формате JSON, а также экспериментальный диалект clickhouse_json, включаемый настройкой enable_json_ast_dialect. #100412 (alexey-milovidov). #113480 (fm4v).
  • Добавлена системная таблица system.stemmers, в которой перечислены все языки стеммеров, доступные для функции stem. #100611 (Ergus).
  • Добавлена поддержка постфиксных операторов стандартного SQL AT TIME ZONE и AT LOCAL в качестве синтаксического сахара для toTimeZone. Выражение expr AT TIME ZONE zone теперь эквивалентно toTimeZone(expr, zone), а expr AT LOCAL — toTimeZone(expr, timeZone()). #106092 (lvzhipin03).
  • Движок таблицы URL и табличная функция url теперь перенаправляют запросы в соответствующий бэкенд в зависимости от схемы URL: file:// обслуживается движком File, s3:///gs:///gcs:///oss:// — движком S3, az:///azure:///abfss:///abfs:// — движком AzureBlobStorage, hdfs:// — движком HDFS, а http(s)://, как и раньше, — движком URL. Настройка url_base применяется до выбора бэкенда по схеме. Перенаправляются только схемы S3, которые разрешаются стандартными url_scheme_mappers; схемы других S3-совместимых поставщиков (cos, obs, …) не перенаправляются — для них нужно напрямую использовать движок или функцию s3. #106093 (alexey-milovidov).
  • Добавлена функция dotProductTransposed (псевдоним scalarProductTransposed), которая вычисляет приближённое скалярное произведение столбца QBit и опорного вектора и дополняет уже существующие функции L2DistanceTransposed и cosineDistanceTransposed. #108100 (alexey-milovidov).
  • В тип данных QBit добавлен необязательный параметр stride (QBit(T, dimension, stride)), который позволяет хранить группы измерений в отдельных потоках, чтобы векторный поиск мог эффективно читать только первые измерения (например, для эмбеддингов Matryoshka). Транспонированные функции расстояния принимают необязательный четвёртый аргумент used_dims, позволяющий читать меньшее число измерений. #108103 (alexey-milovidov).
  • Добавлена поддержка типа элементов Int8 в типе данных QBit: теперь можно хранить квантованные 8-битные целочисленные векторы и выполнять по ним векторный поиск с помощью транспонированных функций расстояния (L2DistanceTransposed, cosineDistanceTransposed). #108105 (alexey-milovidov).
  • Новая функция randomHadamardTransform(vector[, seed[, output_dims]]): детерминированное рандомизированное преобразование Адамара для вектора чисел с плавающей точкой — ортогональный поворот с сохранением нормы, полезный для предварительной обработки эмбеддингов перед квантованием, а также (при усечении) в качестве случайной проекции Джонсона–Линденштраусса / подвыборочного рандомизированного преобразования Адамара. #108227 (alexey-milovidov).
  • Реализована агрегатная функция mergedJSONPatch для агрегации JSON-значений по принципу merge-patch в стиле RFC 7396, с поддержкой слияния состояний и использования в AggregatingMergeTree. Чтобы получить последнее состояние, можно агрегировать JSON-столбец, используя в качестве ключа сортировки метку времени или другой столбец, задающий порядок. #108349 (larryluogit).
  • Добавлена функция xxHash64Spark, которая вычисляет совместимые со Spark значения xxHash64 для входных значений типа String и NULL с seed 42 и возвращает Int64. #108436 (lalitium).
  • Добавлена функция digits(n, offset[, length]), которая возвращает число из n, начинающееся с позиции offset(1-indexed) и содержащее length цифр. Если length не указан, функция возвращает число от позиции offset до конца. #109012 (1000ms).
  • Добавлена арифметическая функция sqr для вычисления квадрата числа. #109061 (lalitium).
  • Добавлены квантованные транспонированные функции расстояния cosineDistanceTransposedQuantized, L2DistanceTransposedQuantized и dotProductTransposedQuantized, которые работают с QBit(Int8), содержащим коды Lloyd-Max, полученные с помощью quantizeBFloat16ToInt8, и деквантуют сохранённые коды на лету. Опорный вектор с плавающей запятой рассматривается как запрос полной точности и сравнивается с точностью Float32 (запрос типа Float64 приводится к меньшей точности); опорный вектор Array(Int8) также деквантуется, что даёт симметричное расстояние между квантованными векторами. #109405 (alexey-milovidov).
  • Добавлена новая функция dictGetRoot, которая возвращает самого верхнего предка (корень) ключа в иерархическом словаре. Это удобная альтернатива выражению dictGetHierarchy(dict_name, key)[-1]. #109459 (alexey-milovidov).
  • Добавлена табличная функция mergeTreeCodecBlockCounts(database, table), которая для каждой комбинации (часть, столбец, подпоток) таблицы MergeTree показывает, сколько сжатых блоков использует каждый кодек. #109623 (rienath).
  • Добавлена функция notHas — отрицание has для массивов, map и JSON. Если haystack — константный массив, настройка optimize_rewrite_has_to_in (включена по умолчанию) переписывает notHas(constant_array, x) в x NOT IN constant_array, поэтому функция выполняется через поиск по множеству и, как и NOT IN, может отсекать данные по индексу первичного ключа. #109926 (nihalzp).
  • Добавлен геопространственный тип данных MultiPoint, который хранится как Array(Point) и входит в тип Geometry. #109951 (davidmenggx).
  • Функции arrayElement (оператор vec[n]) и arraySlice теперь поддерживают тип данных QBit: qbit[n] возвращает n-й элемент вектора с полной точностью, а arraySlice(qbit, offset, length) возвращает проекцию на подмножество измерений. Обе функции читают только битовые плоскости нужных групп stride, а срезы, выровненные по границам групп stride, переиспользуют сохранённые потоки без копирования. #109953 (Utkal059).
  • Добавлен токенизатор splitByRegexp для текстовых индексов и функции tokens. Он разбивает входные данные на токены, используя регулярное выражение в качестве разделителя, например tokenizer = splitByRegexp('[^\p{L}\p{N}#+]+'). Это позволяет сохранять токены со специальными символами, например C++ или C#, которые другие токенизаторы разбили бы на части. #110002 (Ergus).
  • Добавлены функции geometryIntersectCartesian и geometryIntersectSpherical, которые определяют, пересекаются ли две геометрии. В отличие от polygonsIntersectCartesian/polygonsIntersectSpherical, они принимают любой геометрический тип данных (Point, LineString, MultiLineString, Ring, Polygon, MultiPolygon), включая общий тип Geometry, причём аргументы могут быть разных типов. #110062 (alexey-milovidov).
  • Нативный модуль чтения ORC теперь поддерживает тип ORC uniontype, сопоставляя его с типом ClickHouse Variant (ранее такие столбцы отклонялись с ошибкой Unsupported ORC type). #110078 (alexey-milovidov).
  • Нативный выходной формат ORC теперь умеет записывать тип ClickHouse Variant, сопоставляя его с ORC uniontype (ранее запись завершалась ошибкой ILLEGAL_COLUMN). #110085 (alexey-milovidov).
  • Добавлены форматы фрейминга, которые выбираются новой настройкой framing_output_format: они мультиплексируют различные части ответа на запрос в едином потоке HTTP-ответа — блоки данных, итоги и экстремумы, пакеты прогресса, события профилирования, журналы сервера и исключения. Реализованы следующие форматы фрейминга: None (по умолчанию, всё работает как прежде), EventStream (события, отправляемые сервером по HTTP), JSONEachPacketBase64 и JSONEachPacketString (по одному JSON-объекту на пакет с данными в кодировке base64 или в виде строки). #110127 (alexey-milovidov).
  • Добавлены табличная функция bigquery и движок таблицы BigQuery для чтения из таблиц Google BigQuery и записи в них, включая общедоступные наборы данных. Структура таблицы определяется по схеме таблицы BigQuery. Для аутентификации поддерживаются токен доступа OAuth, ключ сервисного аккаунта в формате JSON и клиент OAuth с токеном обновления. #110166 (alexey-milovidov).
  • Новая функция aiRedact обнаруживает и маскирует персональные данные (PII) в тексте с помощью LLM-провайдера. Укажите категории для маскирования (например, ['email', 'name']) или передайте пустой массив, чтобы использовать набор категорий PII по умолчанию. Найденные значения заменяются маркером (по умолчанию [REDACTED]). #110464 (davidmenggx).
  • Добавлена функция aiFilter, которая с помощью LLM проверяет, выполняется ли для текста условие, сформулированное на естественном языке, и возвращает UInt8 для использования в WHERE, PREWHERE и JOIN ... ON. #110594 (ylw510).
  • Добавлена поддержка TLS/SSL-подключений к PostgreSQL для движка таблицы PostgreSQL, табличной функции postgresql, движков баз данных PostgreSQL и MaterializedPostgreSQL, а также словарей PostgreSQL: поддерживаются sslmode, сертификаты и ключ, которые задаются либо непосредственно содержимым (sslrootcert_pem, sslcert_pem, sslkey_pem; маскируются как пароли), либо путями (sslrootcert, sslcert, sslkey; принимаются только из именованной коллекции, определённой в конфигурационном файле сервера). #110615 (alexey-milovidov).
  • Табличную функцию postgresql и движок таблицы PostgreSQL теперь можно использовать для подключения к другому серверу ClickHouse по протоколу PostgreSQL (при указании имени таблицы; вариант query(...) пока не поддерживается). Добавлены функции совместимости с PostgreSQL format_type и current_setting. #110760 (alexey-milovidov).
  • Новая функция aiSimilarity, которая вычисляет семантическое сходство двух текстов с помощью модели эмбеддингов. Возвращает Nullable(Float32) в диапазоне [-1, 1], где 1 означает, что тексты идентичны, или NULL, если один из операндов равен NULL или пуст либо для него не удалось вычислить эмбеддинг. #110777 (davidmenggx).
  • Добавлены движки баз данных Remote и RemoteSecure, которые обеспечивают доступ в реальном времени к таблицам базы данных на удалённом сервере ClickHouse и перенаправляют на него запросы SELECT и INSERT. Это аналоги движков баз данных MySQL и PostgreSQL для связи ClickHouse с ClickHouse. #110975 (alexey-milovidov).
  • Поддержка пайп-операторов в SQL-запросах: FROM t |> WHERE x > 1 |> AGGREGATE count() AS c GROUP BY y |> ORDER BY c DESC |> LIMIT 10 — по аналогии с пайп-синтаксисом GoogleSQL. За любым SELECT-запросом может следовать цепочка операторов |>, причём каждый оператор оборачивает предшествующий запрос в подзапрос, поэтому итоговое AST совпадает с AST эквивалентного запроса с вложенными подзапросами. В запросе, начинающемся с секции FROM, секция SELECT теперь необязательна и по умолчанию подразумевается SELECT *. #111151 (alexey-milovidov).
  • Добавлена агрегатная функция gini для вычисления коэффициента Джини по конечным неотрицательным числовым значениям, в том числе при агрегации по группам и распределённой агрегации. #112280 (amirreza1307). #114643 (groeneai).
  • Поддержка анимированных PNG в формате вывода PNG. Столбец t превращает результат запроса в анимацию; масштаб времени для t задаётся настройками output_format_image_time_multiplier_seconds и output_format_image_time_divisor_seconds, а настройка output_format_image_streaming_animation позволяет записывать кадры по мере их формирования запросом, не буферизуя их в памяти. #112846 (alexey-milovidov).
  • В system.mutations добавлен столбец finish_time, в котором фиксируется время завершения мутации. Для незавершённых мутаций и мутаций с неизвестным временем завершения выводится ноль. #113474 (nikitamikhaylov).
  • Добавлен новый тип схемы bucketed для system.metric_log, при котором все метрики хранятся в одном столбце Map(Enum16(...), Int64) с бакетной сериализацией Map на 128 бакетов, а для совместимости для каждой метрики создаётся столбец ALIAS. В результате таблица состоит из нескольких столбцов вместо тысяч, нулевые значения не хранятся, а при чтении одной метрики читается только один из 128 бакетов. Кроме того, к Map с ключами типа Enum теперь можно обращаться по строковому имени значения перечисления, например map['name']. #115380 (alexey-milovidov).
  • Добавлен токенизатор chinese для функции tokens и текстовых индексов MergeTree. Он разбивает китайский текст на слова с помощью словаря и скрытой марковской модели (алгоритм заимствован из jieba) и поддерживает уровни детализации coarse_grained (по умолчанию) и fine_grained. #89945 (amosbird).
  • Добавлена агрегатная функция groupFormat, которая форматирует строки каждой группы в заданном формате вывода и возвращает результат в виде строки. #93201 (wandersofb).
  • Добавлен комбинатор агрегатных функций -Tuple, который независимо применяет базовую агрегатную функцию к каждому элементу столбца типа Tuple и возвращает Tuple с результатами, сохраняя имена элементов: sumTuple(t) для t = (a, b) возвращает (sum(a), sum(b)). Агрегатные функции с несколькими аргументами принимают по одному Tuple на каждый аргумент, сопоставляя их по позиции: corrTuple((a1, a2), (b1, b2)) возвращает (corr(a1, b1), corr(a2, b2)). В отличие от -ForEach для массивов, элементы могут иметь разные типы, при этом типы результатов и имена каждого элемента сохраняются. #98190 (RinChanNOWWW).

Возможности SQL и запросов

  • Добавлена поддержка предложений WHERE в определениях проекций. Проекции с WHERE материализуют только строки, удовлетворяющие предикату, и оптимизатор может использовать их (на основе оценки стоимости), если из условия WHERE запроса следует условие WHERE проекции. #102347 (SBALAVIGNESH123).
  • Добавлена возможность обращаться к таблицам и базам данных через пути URL в HTTP-интерфейсе (например, `/database/table.format.gz?filter=a>0`), а также новые настройки (`http_allow_database_as_path`, `http_allow_table_as_file`, `http_allow_filters_as_path`, `http_allow_filters_as_unrecognized_url_parameters`, `select`, `order`, `sort`, `filter`, `page`, `compression`, `format`, `input_format`, `output_format`, `default_format`, `database`), которые можно комбинировать друг с другом и с уже существующим параметром URL `query`. #105249 (alexey-milovidov).
  • Добавлены движки таблиц Remote и RemoteSecure — постоянные аналоги табличных функций remote и remoteSecure. Теперь, помимо CREATE TABLE ... AS remote(...), работает и CREATE TABLE ... ENGINE = Remote('addresses', db, table, ...). #106189 (alexey-milovidov).
  • Добавлена команда EXPLAIN ANALYZE для анализа производительности запросов: запрос выполняется, а фактические метрики выполнения выводятся в привычном формате плана запроса. #106586 (Fgrtue). #110668 (Fgrtue).
  • Добавлены не зависящие от движка команды SYSTEM STOP, SYSTEM START, SYSTEM PAUSE, SYSTEM CANCEL и SYSTEM REFRESH, а также их общесерверные формы ... ALL BACKGROUND, позволяющие через единый интерфейс управлять фоновой активностью таблиц Kafka, RabbitMQ, NATS, S3Queue/AzureQueue и refreshable materialized view. Для refreshable materialized view они служат псевдонимами существующих команд SYSTEM ... VIEW. В рамках поддержки этих команд для NATS таблицы JetStream теперь подтверждают сообщения только после успешной вставки (семантика «как минимум один раз»; ранее сообщения подтверждались автоматически при доставке и могли теряться, если вставка завершалась ошибкой). Новая настройка nats_wait_for_flush_interval (по умолчанию false, что сохраняет прежнее поведение с низкой задержкой) позволяет держать цикл потребления открытым в течение всего интервала сброса, а не сбрасывать данные на диск сразу после опустошения очереди. Новая настройка nats_commit_on_select позволяет прямому запросу SELECT к таблице JetStream потреблять (подтверждать) прочитанные им сообщения. #107476 (NIKTONIKTO717).
  • Табличные функции и движки таблиц mysql, postgresql и sqlite теперь могут принимать пользовательский запрос (вместо имени таблицы) и передавать его во внешнюю СУБД как есть; запрос записывается либо как подзапрос (SELECT ...), либо как query('SELECT ...'). Структура результирующей таблицы определяется по результату запроса, а сама таблица доступна только для чтения. #107740 (alexey-milovidov).
  • Добавлен табличный движок QueryRunner. Записи, вставляемые в таблицу QueryRunner, представляют собой запросы, которые выполняет движок. Движок можно использовать для асинхронного выполнения запросов, пакетного выполнения сгенерированных запросов, направления запросов на удалённые кластеры, бенчмарков, фаззинга и тестирования с теневым трафиком. #107888 (mstetsyuk).
  • Добавлена поддержка режима рамки окна GROUPS для оконных функций (SQL:2011), например any(price) OVER (PARTITION BY symbol ORDER BY ts GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING). В рамке GROUPS границы отсчитываются целыми группами равных строк — наборами строк с одинаковым значением ключа ORDER BY, — поэтому N PRECEDING/N FOLLOWING означают N групп равных строк до или после группы текущей строки, а не физические строки (ROWS) и не расстояние по значению ORDER BY (RANGE). #108653 (nihalzp).
  • Обычный CREATE MATERIALIZED VIEW ... POPULATE теперь выполняется локально атомарно: подписка представления на новые вставки в исходную таблицу и снимок существующих данных выполняются вместе под кратковременной эксклюзивной блокировкой источника, поэтому строки, вставленные через тот же сервер параллельно с заполнением, больше не теряются и не дублируются (новая настройка materialized_views_populate_atomically, включена по умолчанию). Гарантия распространяется только на локальный путь вставки (вставки, поступающие на другую реплику или через распределённый путь записи, ею не охватываются) и требует источника, способного предоставить зафиксированный снимок (семейство MergeTree и Memory); для других источников, а также для CREATE OR REPLACE / REPLACE и представлений, создаваемых в базах данных Replicated, сохраняется прежнее неатомарное заполнение. Кроме того, POPULATE теперь можно использовать вместе с TO для заполнения целевой таблицы уже имеющимися данными. #108715 (alexey-milovidov).
  • ALTER USER, ALTER ROLE и ALTER SETTINGS PROFILE теперь принимают SET name = value как псевдоним для MODIFY SETTING name = value. Эта форма изменяет отдельные настройки, сохраняя остальные, — в отличие от предложения SETTINGS без модификаторов, которое заменяет весь список настроек. Это снижает риск случайно стереть другие настройки пользователя. #108722 (groeneai).
  • Добавлена поддержка ALTER TABLE ... MODIFY CONSTRAINT [IF EXISTS] name CHECK expr для изменения выражения существующего ограничения без его пересоздания. #108768 (alexey-milovidov).
  • Добавлен алгоритм IEJoin на основе сортировки для JOIN, у которых секция ON содержит два сравнения-неравенства (<, <=, >, >=) между соединяемыми таблицами; он включается добавлением ie_join в настройку join_algorithm. Поддерживаются виды ALL INNER/LEFT/RIGHT/FULL JOIN и SEMI/ANTILEFT/RIGHT JOIN. Ранее такие запросы выполнялись как CROSS JOIN с фильтром (только INNER), что на больших таблицах работает значительно медленнее. #109920 (vdimir).
  • Добавлена новая системная таблица system.user_query_log, в которой каждый пользователь видит собственные записи журнала запросов без доступа к таблице журнала запросов. Исходная реализация и идея принадлежат Yue Ni (@niyue). #110156 (alexey-milovidov).
  • Новая настройка run_query_in_background. Сервер принимает запрос, сразу возвращает пустой результат и выполняет запрос до конца независимо от состояния соединения. Результат отбрасывается. Отслеживать запрос можно по его query_id в system.processes и system.query_log. Настройка предназначена для длительных запросов, таких как INSERT ... SELECT, CREATE TABLE … AS SELECT или CREATE MATERIALIZED VIEW … POPULATE, которые не должны прерываться при разрыве соединения. #112816 (mstetsyuk).
  • Добавлена поддержка ALTER TABLE … MODIFY PROJECTION для изменения настроек уровня проекции (например, index_granularity) у существующей проекции без её перестроения. Новые настройки применяются отложенно, в ходе слияний. #113343 (diegomestre2).
  • Каталог движка таблиц S3 для озер данных теперь поддерживает не только запросы к существующим таблицам, но и INSERT. #113505 (scanhex12).
  • Каталог Iceberg теперь поддерживает каталог Snowflake Horizon с параметром catalog_type = 'horizon', что позволяет читать и записывать данные в таблицы Iceberg, управляемые Snowflake. #114547 (melvynator).
  • Добавлена настройка skip_unavailable_shards_mode (также доступна как настройка движка Distributed), которая определяет, какие исключения от удалённого сегмента молча игнорируются при включённой настройке skip_unavailable_shards. Это позволяет точнее управлять поведением запросов в распределённых средах. #79091 (byte-sourcerer).

Хранилище, озёра данных и объектное хранилище

  • Добавлена поддержка формата файлов Puffin (https://iceberg.apache.org/puffin-spec/). Теперь этот формат можно использовать в табличных функциях file, url, s3 и других. #103936 (scanhex12).
  • Для таблиц MergeTree добавлен формат хранения частей данных «packed», при котором все файлы части хранятся в одном архиве (data.packed), а не в отдельном файле для каждого потока. Он управляется настройками min_bytes_for_full_part_storage, min_rows_for_full_part_storage и min_level_for_full_part_storage и по умолчанию отключён. Примечание о совместимости: как только таблица начинает записывать части в формате packed, более старые версии сервера уже не смогут их прочитать, поэтому после включения этого формата откатить сервер на предыдущую версию будет невозможно. #108118 (Algunenano).
  • Для движка таблиц NATS добавлена настройка nats_credentials, позволяющая задавать учётные данные NATS непосредственно в виде строки (с тем же содержимым, что и в файле .creds). #110733 (addshore).

Форматы данных и ингестия

  • Добавлен формат вывода HiveText, записывающий данные в текстовом представлении Apache Hive LazySimpleSerDe. Поля разделяются символом \x01, строки — разделителем, заданным новой настройкой format_hive_text_rows_delimiter (по умолчанию \n), а для вложенных значений Array, Map и Tuple используется список разделителей Hive. Вывод рассчитан на стандартный LazySimpleSerDe в Hive и не симметричен входному формату HiveText в ClickHouse в части вложенных значений и пользовательских разделителей строк. #107582 (alexey-milovidov).
  • Добавлен формат вывода GeoJSON для записи документов GeoJSON FeatureCollection, в которых каждой строке соответствует один объект (feature). Новая настройка format_geojson_validate_geometry (включена по умолчанию) проверяет корректность геометрий GeoJSON при чтении и записи; входной формат GeoJSON теперь определяет тип id как Nullable(String), что позволяет отличать отсутствующие или равные null идентификаторы от пустых строк. #108065 (nihalzp).

Настройки, доступ и обсервабилити

  • Добавлена встроенная страница поиска по документации, доступная по пути /docs HTTP-интерфейса. Она обеспечивает мгновенный поиск по таблице system.documentation и отображает справочную документацию (с подсветкой синтаксиса, математическими формулами и перекрёстными ссылками). #108345 (alexey-milovidov).
  • Добавлен японский токенизатор для текстовых индексов и функций tokens/hasAnyTokens/hasAllTokens на основе морфологического анализатора MeCab. Словарь загружается во время выполнения из каталога, указанного в конфигурации сервера, и перед использованием проверяется по контрольной сумме SHA-256. #111420 (Ergus).
  • Добавлена новая настройка файлового кэша system_cache_extensions, которая определяет, какие файлы хранятся в системном кэше при включённой настройке use_split_cache. #111575 (kirillgarbar).
  • Добавлена настройка always_fetch_mutated_part, которая позволяет реплике загружать мутированные части с других реплик, а не выполнять мутации локально. #113020 (rorylshanks).

Другие новые возможности

  • Добавлена поддержка WITH TIES для отрицательного LIMIT. #100930 (nihalzp).
  • Добавлены настройки восстановления restore_table_data, restore_access_entities и restore_functions, позволяющие точно управлять тем, что именно восстанавливается. Они могут переопределять structure_only для отдельных категорий — например, structure_only=true, restore_access_entities=true восстанавливает определения таблиц и объекты управления доступом без данных таблиц. #102402 (fm4v).
  • Теперь отложенную загрузку можно настроить для каждого словаря отдельно с помощью параметра dictionary_lazy_load в определении словаря; он переопределяет глобальную настройку сервера dictionaries_lazy_load. Таким образом, одни словари могут загружаться отложенно, а другие — сразу. #108314 (mstetsyuk).
  • Оператор индексирования массива теперь принимает в качестве индекса массив целых чисел: arr[indexes] возвращает элементы во всех указанных позициях, что эквивалентно arrayMap(i -> arr[i], indexes). #108371 (ucasfl).
  • Добавлены функции geoToUTM, UTMToGeo, geoToMGRS и MGRSToGeo для преобразования географических координат WGS84 в системы координат UTM и MGRS и обратно. #108939 (alexey-milovidov).
  • Добавлены команды SYSTEM UNLOAD DICTIONARY и SYSTEM UNLOAD DICTIONARIES, освобождающие память, занятую словарём, без удаления его определения. При следующем обращении словари будут загружены повторно (отложенно). #109639 (Manerone).
  • Добавлен новый токенизатор icu для текстовых индексов и функций tokens, hasAnyTokens и hasAllTokens, обеспечивающий сегментацию слов Unicode с учётом локали (в том числе сегментацию на основе словаря для таких языков, как китайский, японский и тайский). #109940 (Ergus).
  • Добавлен новый кодек ZXC — асимметричный LZ-кодек с медленным сжатием и очень быстрой декомпрессией; по коэффициенту сжатия он занимает промежуточное положение между LZ4 и ZSTD. #110620 (alexey-milovidov).
  • Добавлена настройка s3_base, позволяющая разрешать относительные URL в табличных функциях s3, s3Cluster, gcs и oss, а также в движке таблицы S3 относительно базового URL S3. Добавлен движок баз данных URL, который интерпретирует имена таблиц как URL, разрешая их относительно необязательного базового адреса, и передаёт их соответствующему бэкенду. #111512 (alexey-milovidov).
  • Для url() и движка URL реализовано раскрытие подстановочных шаблонов: ClickHouse читает индексные HTTP-страницы (HTML или текстовые листинги каталогов) и извлекает из них подходящие URL. Шаблоны сопоставляются с компонентом пути URL; при этом действуют ограничения на размер индексной страницы и на количество читаемых каталогов. #95181 (niyue).
  • Для kafka_sasl_mechanism добавлено поддерживаемое значение AWS_MSK_IAM, позволяющее ClickHouse аутентифицироваться в Amazon MSK с помощью ролей IAM без необходимости управлять учётными данными SASL/SCRAM. #96100 (kalavt).
  • В текстовый индекс добавлен постпроцессор, преобразующий токены после токенизации. #98939 (Ergus).

Экспериментальные возможности

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

  • Добавлены «драйверы» для исполняемых пользовательских функций. Драйвер, объявленный в <user_defined_executable_function_drivers_config>, можно использовать в CREATE FUNCTION name ARGUMENTS (...) RETURNS T ENGINE = DriverName(...) AS '...code...', чтобы при создании функции скомпилировать или иным образом обработать фрагмент пользовательского кода и получить готовую к запуску исполняемую UDF. Полученная конфигурация сохраняется в <dynamic_user_defined_executable_functions_path>, а исходный запрос записывается как ATTACH FUNCTION, поэтому функция не теряется при перезапуске сервера. Экспериментальный драйвер c_function_body (proof-of-concept) компилирует и выполняет тела функций на C в изолированных контейнерах Docker в режиме executable_pool. #105131 (alexey-milovidov).
  • Запросы Prometheus Query API к /api/v1/query и /api/v1/query_range теперь записываются в system.query_log с метриками read_rows и read_bytes. #106611 (JTCunning).
  • Добавлена поддержка чтения с распределённым планом запроса для SELECT ... FINAL по таблицам семейства MergeTree при включённой настройке make_distributed_plan. #108148 (davenger).
  • Добавлено экспериментальное выполнение запросов к MergeTree с параллельными репликами на основе плана. #108504 (devcrafter).
  • Добавлена экспериментальная табличная функция eval, которая вычисляет константное выражение в строку запроса и выполняет полученный одиночный SELECT-запрос. По умолчанию функция отключена; включить её можно настройкой allow_experimental_eval_table_function. Автор: Yue Ni #110132 (alexey-milovidov).
  • Параллельные реплики на основе плана (parallel_replicas_plan_based): граница между локальной и удалённой частью теперь определяется оптимизацией на уровне плана поверх обычного плана запроса, а запросы к представлениям с UNION распараллеливаются без parallel_replicas_allow_view_over_mergetree. Запросы с IN (subquery) теперь не завершаются с ошибкой, а переключаются на локальный план. #111063 (devcrafter). #112443 (devcrafter).
  • Повышена безопасность экспериментальных функций ИИ: по умолчанию запрещены небезопасные (http) конечные точки для удалённых хостов (новая настройка ai_function_allow_insecure_endpoint), по умолчанию ограничено число исходящих вызовов API на запрос (ai_function_max_api_calls_per_query теперь по умолчанию равно 1000), а ответы провайдера с ошибками перед записью в логи очищаются от чувствительных данных. #111286 (george-larionov).
  • Параллельные реплики на основе плана (parallel_replicas_plan_based) теперь распределяют подходящие JOIN (INNER, LEFT, RIGHT, включая SEMI/ANTI): весь JOIN выполняется во фрагменте распределённого плана, при этом одна сторона координируется между репликами, а другая рассылается на все реплики. #112268 (devcrafter).
  • Теперь вместо простого QUERY_WAS_CANCELLED выводится ошибка, из-за которой был отменён распределённый запрос (make_distributed_plan = 1). Ранее фактическая ошибка сбойной задачи воркера была видна только в логе сервера. #112590 (davenger).
  • Добавлена поддержка распределённого выполнения планов запросов с IN (subquery) без переписывания в JOIN. Множество строится один раз на инициаторе, а его значения передаются вместе с задачами воркеров. Принудительное переопределение rewrite_in_to_join удалено; переписывание по-прежнему можно включить явной настройкой. #113826 (davenger).
  • Запрос с распределённым планом (make_distributed_plan) теперь останавливает вышестоящие стадии, как только условие LIMIT выполнено, а не вычисляет полный результат, чтобы затем его отбросить. #114806 (davenger).
  • Исправлена ошибка Illegal type Decimal(18, 0) of argument of function toIntervalNanosecond, возникавшая, когда в запросе PromQL используется offset внутри селектора диапазона, например rate(m[2m] offset 5m). #114997 (nikitamikhaylov).
  • Добавлена поддержка агрегации GROUPING SETS в распределённых планах, построенных оптимизатором Cascades (make_distributed_plan = 1, enable_cascades_optimizer = 1). #115426 (davenger).
  • Таблицы TimeSeries теперь могут вести таблицу «recent samples»: если новой настройке движка recent_samples_ttl_seconds задано ненулевое значение, движок создаёт копию таблицы образцов с TTL (с партиционированием по recent_samples_partition_by, по умолчанию — по дням), которая пополняется при каждой вставке, а запросы PromQL, временной диапазон которых укладывается в окно TTL, автоматически читают данные из неё. Благодаря этому правила оповещений и записи, а также панели мониторинга с коротким диапазоном на больших таблицах работают в несколько раз быстрее. Чтение из этой таблицы в приоритетном порядке можно отключить с помощью новой настройки уровня запроса time_series_prefer_recent_samples_table. #115441 (nikitamikhaylov).
  • Распределённые планы запросов (make_distributed_plan) теперь оперативно останавливают бездействующие вышестоящие стадии после выполнения условия LIMIT: бездействующий приёмник обмена считывает NoMoreDataNeeded сразу после его поступления, а бездействующий источник обмена обнаруживает, что его выход закрыт, и передаёт сигнал остановки вверх по цепочке. Ранее такие стадии продолжали читать и вычислять данные, которые никто не использовал. #115690 (davenger).
  • Механизм автоматических параллельных реплик теперь может собирать статистику во время выполнения и включать параллельные реплики для поддерживаемых запросов, если включена настройка parallel_replicas_plan_based. #115788 (devcrafter).
  • Добавлен экспериментальный стоимостной оптимизатор Cascades для распределённых планов запросов, который включается настройкой enable_cascades_optimizer = 1 совместно с make_distributed_plan = 1. На основе оценочной стоимости он выбирает стратегию соединения (shuffle, broadcast, replicated или local), агрегации (двухфазная, shuffle или локальная), двухстадийный распределённый top-N, а также параллельное или реплицированное чтение, при необходимости добавляя операторы обмена. #86353 (davenger).

Хранилище, озера данных и индексы

  • Добавлен SLRU-кэш в памяти для десериализованных файлов метаданных Paimon (списков манифестов и манифестов). Если он включен настройкой use_paimon_metadata_files_cache, повторные запросы к одной и той же таблице Paimon не загружают и не разбирают метаданные из объектного хранилища заново. #104657 (Binnn-MX).
  • Экспериментальный ReaderExecutor (use_reader_executor, по умолчанию выключен) теперь может держать открытым удаленное соединение с источником и повторно использовать его при последовательных чтениях, что сокращает количество запросов к объектному хранилищу при сканировании. #107735 (CheSema).
  • В путь чтения экспериментального ReaderExecutor (use_reader_executor, по умолчанию выключен) добавлен файловый кэш со сквозным чтением (read-through). #110029 (CheSema).
  • Добавлена экспериментальная настройка MergeTree allow_experimental_adaptive_codec_selection. Если она включена, при слияниях и мутациях для столбцов с кодеком по умолчанию в каждом блоке выбирается кодек, обеспечивающий наименьший размер данных. #111834 (rienath).
  • В путь чтения экспериментального ReaderExecutor (use_reader_executor, по умолчанию выключен) добавлен уровень кэша страниц в пространстве пользователя. При промахе исполнитель теперь заполняет кэш страниц в пространстве пользователя и обслуживает из него последующие чтения без копирования (zero-copy). #114890 (CheSema).
  • Компакция файлов манифестов Iceberg теперь доступна через OPTIMIZE TABLE ... MANIFEST и позволяет сократить количество файлов метаданных. Эта возможность включается настройкой allow_experimental_iceberg_compaction. #98178 (SmitaRKulkarni).

Функции, форматы и ИИ

  • Экспериментальная возможность: запрос SELECT count(*) FROM t WHERE col <op> default(col) выполняется на основе статистики разреженности по каждому столбцу из serialization.json вообще без сканирования данных, если предикат точно разделяет столбец на значения по умолчанию и прочие значения. #105890 (Algunenano).
  • Добавлено экспериментальное семейство векторных кодеков Quantize(...) и включаемое по желанию двухэтапное переписывание запросов приблизительного векторного поиска с использованием сопутствующих квантованных потоков. #108565 (shankar-iyer).
  • Возвращён экспериментальный кодек сжатия с потерями и ограниченной погрешностью SZ3 для столбцов Float32/Float64 (и массивов из них). Для него требуется настройка allow_experimental_codecs. #108788 (alexey-milovidov).
  • Исправлено чтение данных, сжатых экспериментальным кодеком SZ3('ALGO_LORENZO_REG', ...), которое ранее завершалось ошибкой CORRUPTED_DATA, а также устранено неопределённое поведение при сжатии экспериментальным кодеком SZ3 неконечных значений с плавающей запятой (NaN и бесконечностей). #110762 (alexey-milovidov).
  • PromQL: функции даты и времени (hour(), minute(), month(), year(), day_of_week(), day_of_month(), day_of_year(), days_in_month()) теперь можно вызывать без аргументов — по умолчанию используется vector(time()), как в Prometheus. #111869 (valerypetrov).
  • PromQL: исправлены операции над мгновенными векторами без тегов, например vector(1) + vector(2), topk(1, vector(1)), label_replace(vector(1), ...) и бинарные операторы с on(), которые завершались ошибкой типа. #111872 (valerypetrov).
  • PromQL: реализована функция deriv; исправлена ошибка, из-за которой лежащая в её основе агрегатная функция при временных метках с миллисекундным разрешением возвращала значения в 1000 раз меньше корректных. #112360 (valerypetrov).
  • Оптимизация чтения в порядке сортировки теперь применяется к запросам с ORDER BY при включённой настройке parallel_replicas_plan_based: сортировка передаётся на реплики, а результаты объединяются на initiator, поэтому каждая реплика читает данные в порядке ключа сортировки. Также исправлена ошибка Unknown function __topKFilter для ORDER BY по столбцу, не входящему в первичный ключ, при включённой настройке. #114315 (devcrafter).
  • Исправлено чтение при векторном поиске после повторной загрузки части данных (например, после ATTACH или перезапуска сервера): части больше не теряют подстолбцы кодека Quantized, поэтому поиск читает квантованные подстолбцы, а не откатывается к столбцу с полной точностью. #114763 (shankar-iyer).
  • Экспериментальный движок таблицы TimeSeries больше не применяет кодек Gorilla к автоматически создаваемым столбцам value внутренней таблицы samples; теперь по умолчанию для них используется CODEC(ZSTD(1)). Для явно объявленных столбцов сохраняются кодеки, указанные пользователем. Значение по умолчанию для столбца timestamp не изменилось (CODEC(DoubleDelta, ZSTD(1))). #112110 (nikitamikhaylov). #114790 (nikitamikhaylov).
  • Добавлена поддержка ROLLUP, CUBE, GROUPING SETS и функции grouping в запросах, выполняемых с make_distributed_plan = 1. #114950 (davenger).
  • В экспериментальный кодек ALP добавлены вариант Real Doubles (RD) и необязательный аргумент ALP(AUTO|STD|RD). Теперь ALP без аргументов не использует всегда STD, а автоматически выбирает между уже существующей схемой STD и RD. #99654 (nazarii-piontko).

Другие экспериментальные возможности

  • Добавлена статическая привязка партиций к сегментам для StorageKafka2 с помощью настроек kafka_partition_shard_num и kafka_shard_count, что позволяет нескольким сегментам ClickHouse детерминированно потреблять непересекающиеся подмножества партиций Kafka. #108886 (JingYanchao).
  • Теперь для аутентификации в OneLake можно использовать заранее полученный Bearer-токен, указав его в настройке onelake_bearer_token вместо onelake_client_id и onelake_client_secret. Это избавляет от необходимости передавать долгоживущий секрет клиента. Токен не обновляется, поэтому после истечения срока его действия базу данных необходимо пересоздать. #109104 (asya-ch).
  • Исправлено значение data_uncompressed_bytes для индексов пропуска, упакованных в skp_idx.packed (через packed_skip_index_max_bytes): вместо несжатого размера сообщался сжатый, что к тому же могло препятствовать активации distributed_index_analysis. #109272 (Algunenano).
  • В экспериментальный HTTP-обработчик Prometheus remote-write v1 добавлена поддержка сжатия Zstandard. #110907 (JTCunning).
  • PromQL: реализованы функции clamp, clamp_min, clamp_max и round. #111870 (valerypetrov).
  • PromQL: quantile с уровнем квантиля вне диапазона [0, 1] теперь, как и Prometheus, возвращает -Inf/+Inf/NaN вместо ошибки, а histogram_quantile по примеру Prometheus игнорирует входные серии, у которых метка le отсутствует или не поддаётся разбору. #111871 (valerypetrov).
  • PromQL: реализованы функции changes() и resets(). #112352 (valerypetrov).
  • Исправлен сбор статистики вставок и запросов, поступающих через конечную точку Prometheus remote-write. #112825 (JTCunning).
  • PromQL: при взятии остатка от деления на бесконечный делитель конечные значения теперь сохраняются. #113746 (fallintoplace).
  • Литеральные символы перевода строки в обычных строках PromQL в кавычках теперь отклоняются. #114381 (fallintoplace).
  • Очень большое значение distributed_plan_workers_num больше не приводит к аварийному завершению сервера с std::length_error при включённых экспериментальных настройках make_distributed_plan и enable_cascades_optimizer. Теперь такое количество узлов отклоняется с ошибкой INVALID_SETTING_VALUE. #115398 (groeneai).
  • Для таблиц TimeSeries реализована конечная точка /api/v1/series Prometheus HTTP API: поддерживаются селекторы серий match[] (повторяющиеся значения объединяются), необязательный временной диапазон start/end и необязательный параметр limit. #115676 (nikitamikhaylov).

Повышение производительности

Производительность JOIN и агрегации

  • Кэш условий запроса теперь используется и для запросов, проходящих через динамическую фильтрацию TopK (ORDER BY ... LIMIT n). Запись QCC партиционируется по параметрам плана TopK, поэтому один и тот же запрос повторно использует закэшированные результаты фильтра WHERE, а другое значение LIMIT, другой столбец или направление сортировки приводят к созданию новой записи. #104478 (alexey-milovidov).
  • LIMIT теперь проталкивается в агрегацию по порядку, что позволяет досрочно завершать выполнение, когда ключ GROUP BY совпадает с ключом ORDER BY и ключом сортировки таблицы. Это значительно сокращает количество прочитанных строк. #104859 (thevar1able).
  • Настройка allow_aggregate_partitions_independently теперь включена по умолчанию. Если ключ GROUP BY соответствует ключу партиционирования, ClickHouse может агрегировать каждую партицию независимо и пропускать этап глобального слияния. Эвристики времени выполнения автоматически отключают эту оптимизацию, если структура партиций делает её невыгодной (слишком мало или слишком много партиций либо сильный перекос их размеров). #105128 (alexey-milovidov).
  • Настройка read_in_order_use_virtual_row теперь включена по умолчанию. При чтении по порядку первичного ключа (например, ORDER BY primary_key LIMIT n) из таблицы с большим количеством частей читаются только те части, которые действительно могут повлиять на результат (плюс окно упреждающего чтения не более чем из max_threads частей, сохраняющее параллельность чтения), что значительно снижает пиковое потребление памяти. #106215 (alexey-milovidov).
  • Снижено использование памяти и повышена производительность JOIN. Правая сторона хеш-JOIN теперь использует компактную 8-байтовую ссылку на строку на основе индекса, поэтому записи хеш-таблицы для ALL JOIN при любом типе ключа стали такими же компактными, как и для ANY JOIN. По результатам тестов на крупных запросах с parallel_hash JOIN — INNER и ANY JOIN таблиц размером 100–300 миллионов строк по ключам UInt64 и String, как с уникальными, так и с повторяющимися ключами — медианный запрос ускорился примерно на 12 % и потреблял примерно на 15 % меньше пиковой памяти, причём ни один запрос не замедлился. Наибольший выигрыш получили INNER JOIN по ключам UInt64 (медианное ускорение около 21 % при снижении потребления памяти на 38 %). #107189 (harikrishnan94).
  • Добавлен алгоритм перебора порядка JOIN dpsub, который строит оптимальные планы JOIN с меньшими накладными расходами на оптимизацию, чем dpsize, и поддерживает не только внутренние JOIN. #107351 (fkastrati).
  • Одноуровневые агрегации с небольшим использованием памяти больше не преобразуются в двухуровневые: для состояния агрегации подключается отдельный трекер памяти вместо учёта памяти всего запроса. #107490 (m-selmi).
  • При анализе агрегирующих запросов больше не строится полное AST запроса: ключ кэша статистики размеров хеш-таблицы агрегации теперь вычисляется по плану запроса, а не по AST. #107643 (novikd).
  • Добавлена возможность переключаться с hash JOIN, использованного при первом выполнении запроса, на parallel_hash при последующих выполнениях на основе статистики, собранной во время первого выполнения. #108125 (m-selmi).
  • Размер хеш-таблицы из статистики JOIN, собранной во время выполнения, теперь используется для оптимизации размера runtime-фильтров JOIN при последующих выполнениях запроса. Поведение управляется новой настройкой join_runtime_filter_size_from_hash_table_stats. #108313 (m-selmi).
  • Ускорено выполнение и снижено использование памяти для запросов DISTINCT к партиционированным таблицам MergeTree: теперь строки каждой партиции обрабатываются в пределах одного потока, поэтому предварительный DISTINCT каждого потока работает с непересекающимся набором ключей, а один и тот же набор ключей больше не встречается в нескольких предварительных DISTINCT. Оптимизация применяется, когда выражение партиционирования является детерминированной функцией от столбцов DISTINCT, и включается на основе эвристической оценки стоимости, учитывающей число партиций и их перекос (это поведение можно принудительно включить настройкой force_distinct_partitions_independently, по умолчанию отключённой). Свойство непересекаемости по партициям также передаётся через шаги Expression, Filter и ARRAY JOIN к итоговым потребителям DISTINCT, LIMIT BY и GROUP BY, чтобы они тоже могли пропустить слияние. Поведение управляется новыми настройками allow_distinct_partitions_independently (включена по умолчанию) и max_number_of_partitions_for_independent_distinct, позволяющими тонко настроить эвристику. #108326 (nihalzp).
  • Фильтры времени выполнения теперь строятся по ключам равенства, даже если предложение ON содержит также предикаты неравенства. Благодаря этому в смешанных соединениях по равенству и неравенству в hash join поступает меньше строк. На LEFT ANTI JOIN это изменение не влияет. #108579 (29antonioac).
  • Порог программной предвыборки (prefetch) для хеш-таблиц агрегации и JOIN снижен с 4 * L2 cache size до L2 cache size, так что предвыборка включается, как только хеш-таблица перестаёт помещаться в L2. Это устраняет регрессию производительности GROUP BY и JOIN на хеш-таблицах среднего размера (~1–8 МиБ) на платформах с большим заявленным объёмом L2 (например, aarch64 с L2 объёмом 2 МиБ). #108655 (groeneai).
  • Улучшена производительность оконных функций. Оконные запросы к широким таблицам, содержащие SELECT *, теперь потребляют значительно меньше памяти и выполняются быстрее. Оконные агрегаты, включая quantile*, uniq* и groupArray, работают быстрее с OVER () и OVER (ORDER BY ... RANGE ...). Функция cume_dist также стала быстрее, а окна с PARTITION BY или ORDER BY теперь эффективнее работают со столбцами, содержащими много повторяющихся значений. #108688 (nihalzp).
  • Запросы агрегации без агрегатных функций теперь используют методы на основе HashSet вместо HashMap (для поддерживаемых типов ключей). Наблюдалось ускорение до 1,8 раза. #108862 (nickitat).
  • Снижены накладные расходы, связанные с конкуренцией за блокировки, в алгоритме JOIN parallel_hash. #108938 (m-selmi).
  • Добавлено новое значение join_algorithm — parallel_full_sorting_merge: для хеш-совместимых соединений по равенству оно разбивает полное сортирующее соединение слиянием по хешу ключей соединения на независимые соединения слиянием для каждого сегмента, выполняемые во всех потоках. При этом сохраняется характерное для соединения слиянием низкое потоковое потребление памяти, но обработка распараллеливается (в бенчмарке — примерно в 2,4 раза быстрее и примерно в 3,3 раза меньше памяти, чем parallel_hash). Соединения ASOF откатываются к одиночному full_sorting_merge; для хеш-несовместимых типов ключей (с плавающей точкой, JSON, Object, Dynamic) пропускается только переписывание с хеш-распределением, при этом их по-прежнему можно сегментировать на источнике по диапазонам первичного ключа, если включена настройка query_plan_join_shard_by_pk_ranges. Результат не упорядочен. #109005 (alexey-milovidov).
  • Статистика столбцов теперь по умолчанию материализуется при INSERT, если текущий активный размер таблицы вместе с размером записываемого блока не превышает значения новой настройки materialize_statistics_on_insert_max_table_size (по умолчанию 25 GiB). Проверка выполняется для каждого записываемого блока, поэтому при первой массовой загрузке в пустую таблицу статистика всё равно может материализоваться для каждого записанного блока. Благодаря этому стоимостный оптимизатор JOIN получает точные оценки для только что загруженных таблиц измерений и не выбирает заведомо неудачный порядок JOIN (например, запросы TPC-H Q5 и Q8 больше не завершаются по тайм-ауту при scale factor 40). Для крупных устоявшихся таблиц фактов статистика, как и прежде, материализуется во время слияний. #109454 (alexey-milovidov).
  • Оптимизирована агрегатная функция uniqCombined для агрегации без ключа. #109794 (CurtizJ).
  • Оптимизированы агрегатные функции uniqHLL12 и uniqCombined. #109831 (CurtizJ).
  • Обработка строк без соответствия в алгоритме JOIN parallel_hash теперь распараллеливается ещё в двух случаях: при наличии остаточного фильтра и при малых ключах JOIN (одноуровневая хеш-таблица). #110008 (m-selmi).
  • Фильтр теперь проталкивается ниже оконной функции, если предикат ссылается только на столбцы PARTITION BY окна. Такой предикат, записанный после окна (во внешнем предложении WHERE вокруг подзапроса с окном или в виде конъюнкта в QUALIFY), теперь доходит до хранилища и позволяет использовать отсечение по первичному ключу и партициям, индексы пропуска данных и проекции. Например, запрос SELECT ... row_number() OVER (PARTITION BY key ORDER BY ts) AS rn ... QUALIFY rn = 1 AND key = 'x' больше не читает всю таблицу и не применяет оконную функцию ко всем её строкам. #110114 (groeneai).
  • При join_use_nulls = 1 предложение WHERE, отбрасывающее NULL и ссылающееся на столбцы обеих сторон внешнего JOIN (например, WHERE l.k = 42 AND r.k = 42), теперь преобразует JOIN в INNER (или LEFT/RIGHT) и выполняет отсечение по первичному ключу — так же, как при join_use_nulls = 0. Ранее в этом случае преобразование не выполнялось, и обе таблицы читались целиком. #110121 (groeneai).
  • Оптимизированы функции uniq, uniqExact и uniqHLL12 при агрегации без ключа. #110150 (CurtizJ).
  • JOIN, условие ON которого всегда ложно (например, ON 1 = 2, ON NULL или условие, сводящееся к false, такое как a.t = 'A' AND a.t = 'B'), больше не читает сторону, не влияющую на результат. Новая оптимизация плана запроса заменяет пустым источником те входные стороны, которые не могут дать ни одной строки. Управляется настройкой query_plan_short_circuit_constant_false_join (по умолчанию включена). #110234 (groeneai).
  • Финальное слияние одноуровневых хеш-таблиц агрегации теперь распараллелено: пространство ключей разбивается на непересекающиеся хеш-партиции, которые потоки сливают независимо друг от друга (настройка enable_parallel_single_level_merge, включена по умолчанию). Это ускоряет запросы GROUP BY, в которых хеш-таблицы отдельных потоков не достигают порога перехода к двухуровневой структуре, но слияние занимает основную часть времени выполнения. #110395 (nihalzp).
  • Ключи агрегации из одного String теперь используют более компактное представление хеш-таблицы, что ускоряет нагрузки GROUP BY с преобладанием строковых данных. Новая настройка enable_packed_string_keys_in_aggregation включена по умолчанию; если её отключить или задать compatibility ниже 26.8, будет использоваться прежний путь StringHashTable, который может работать быстрее для ключей очень низкой мощности длиной более 11 байт. #110573 (harikrishnan94). #112089 (harikrishnan94).
  • Производительность полного сортирующего соединения слиянием в разреженных сценариях повышена в 1,5–3 раза. #111200 (vdimir).
  • join_runtime_filter_from_fixed_hash_table теперь включается и в случае, когда типы ключей JOIN на стороне проверки и на стороне построения различаются (например, ключ проверки имеет тип Nullable, а ключ построения — нет). #111244 (m-selmi).
  • Повышена производительность RIGHT и FULL JOIN с алгоритмом parallel_hash в случаях, когда правая сторона содержит ключи JOIN со значением NULL или строки, отфильтрованные выражением ON: карты NULL больше не перестраиваются. #111258 (m-selmi).
  • Новый адаптивный алгоритм для параллельного GROUP BY (управляется настройкой enable_adaptive_aggregator, включённой по умолчанию): каждый поток агрегирует данные в собственную хеш-таблицу, пока в ней не наберётся adaptive_aggregator_freeze_threshold ключей, после чего замораживает её. Благодаря этому частые ключи продолжают обновлять небольшие таблицы, помещающиеся в кэш, без какой-либо координации, а редкие ключи по своему хешу направляются в очереди соответствующих бакетов и агрегируются ровно один раз — в ходе параллельного по бакетам слияния. #111459 (nihalzp).
  • Ускорено построчное хеширование значений столбцов JSON/Object, хранящихся в общих данных (используется, например, в uniq/uniqExact по JSON-столбцу и в хешированных ключах GROUP BY/DISTINCT): ColumnDynamic больше не реконструируется для каждого значения. Хеш-значения не изменились. #111501 (valerypetrov).
  • Повышена производительность RIGHT и FULL hash JOIN с несколькими дизъюнктами OR в секции ON, а также RIGHT/FULL JOIN с остаточными условиями (неравенствами). #111590 (m-selmi).
  • Чтение по порядку через JOIN теперь работает и в случае, когда для hash join настроен автоматический порог сброса данных на диск (по умолчанию начиная с 26.5). Если эта оптимизация применяется, JOIN остаётся в памяти и сохраняет порядок левой стороны; чтобы вернуть прежнее поведение, при котором такие JOIN не используются для чтения по порядку и могут свободно сбрасывать данные на диск, установите query_plan_read_in_order_through_spilling_join = 0. Кроме того, ORDER BY ... LIMIT поверх LEFT JOIN с чтением по порядку больше не указывает в качестве планируемого числа читаемых строк размер всей таблицы, поэтому чтение с ранней остановкой больше не приводит к срабатыванию max_rows_to_read при read_overflow_mode = 'throw'. #111973 (alexey-milovidov).
  • Снова включена оптимизация последовательных ключей для агрегации TTL ... GROUP BY во время слияний. Агрегатор создавался со значением min_chunk_bytes_for_parallel_parsing (порог в байтах, по умолчанию 10 MiB) на месте параметра min_hit_rate_to_use_consecutive_keys_optimization (доля попаданий в диапазоне [0, 1], по умолчанию 0.5), из-за чего на этом пути оптимизация всегда оставалась отключённой. На результаты это не влияет. #112314 (groeneai).
  • Отложенная репликация столбцов для ARRAY JOIN больше не теряется при сериализации плана запроса. При serialize_query_plan = 1 узел, выполняющий удалённый фрагмент плана, ранее игнорировал enable_lazy_columns_replication и всегда материализовал каждую реплицированную копию, хотя по умолчанию эта настройка включена. #112330 (groeneai).
  • Условие равенства из предложения WHERE теперь объединяется с условием JOIN, если его операнды имеют разные типы, но общий супертип, например Int32 и Nullable(Int32). Это позволяет преобразовать CROSS JOIN в INNER JOIN. #112630 (m-selmi).
  • Исправлено квадратичное перераспределение памяти при репликации Array, элементы которого содержат значения JSON в общих данных, — например, константного Array(JSON), передаваемого в агрегатную функцию. Объём данных, копируемых такими запросами, рос квадратично с числом строк. #112897 (groeneai).
  • Восстановлено отсечение частей и гранул в случаях, когда границы диапазонного предиката по первичному ключу или ключу партиционирования MergeTree задаются через предложение JOIN ON с константной стороной из одной строки, например SELECT count() FROM t JOIN bounds ON t.d >= bounds.lo AND t.d <= bounds.hi. Начиная с версии 25.2 такой запрос читал все части, а настройка query_plan_use_logical_join_step, с помощью которой раньше можно было вернуть отсечение, в 26.5 устарела, и восстановить его стало невозможно. #112957 (groeneai).
  • Устранена кубическая сложность планирования запроса для JOIN с таблицей Merge поверх множества таблиц с разной структурой. Ранее планирование таких запросов могло занимать минуты, при этом они не реагировали на max_execution_time или KILL QUERY. #113140 (alexey-milovidov).
  • Исправлена регрессия производительности: агрегация без ключей GROUP BY при каждом выполнении сериализовала всё поддерево входного плана, включая полное содержимое свёрнутых константных литералов, ради вычисления ключа кэша размера хеш-таблицы, который она всё равно не может использовать. Запрос вида SELECT quantileMerge(arrayJoin(arrayMap(x -> state, range(5000000)))) тратил на оптимизацию плана запроса около 63 мс при каждом выполнении, а теперь — 0,15 мс. #113333 (groeneai).
  • Операторы агрегации PromQL topk, bottomk и limitk теперь вычисляются с помощью потокового плана, состояние выборки которого занимает O(time_steps * k), вместо сбора всех серий в одну строку с промежуточным расходом памяти O(time_steps * series^2). Запросы по метрикам с высокой мощностью, которые раньше завершались ошибкой MEMORY_LIMIT_EXCEEDED, теперь выполняются в ограниченном объёме памяти, а вычисление распараллелено, а не выполняется в одном потоке. #113656 (nikitamikhaylov).
  • Хеш-таблица для каждого бакета в агрегатных функциях timeSeries*ToGrid заменена плоским отсортированным массивом образцов: для упорядоченных входных данных (а это подавляющее большинство случаев) приём образца сводится к добавлению за O(1), а копирование и сортировка каждого бакета при финализации больше не требуются. #113681 (nikitamikhaylov).
  • Подвыражения PromQL, общие для нескольких шагов плана (операнд topk/bottomk/limitk, левая часть or), теперь вычисляются один раз, а не дважды: SQL, генерируемый из PromQL, материализует общие подзапросы. Это избавляет от повторного сканирования таблицы образцов: topk поверх rate при холодном запуске работает примерно в 2 раза быстрее, а запросы правил kubernetes-mixin ускоряются на 10–29 %. #113772 (nikitamikhaylov).
  • Кэш условий запроса теперь включен по умолчанию для запросов, использующих оптимизацию ORDER BY <column> LIMIT n (TopK). Чтобы отключить его, установите use_query_condition_cache_for_top_k = 0. #111492 #114539 (alexey-milovidov).
  • Преобразование состояний агрегации отдельных потоков из одноуровневых в двухуровневые перед слиянием теперь выполняется параллельно. Это устраняет замедление в 2–3 раза коротких запросов с GROUP BY и тяжелыми состояниями агрегатных функций (например, COUNT(DISTINCT ...), ClickBench Q10/Q11) на машинах с очень большим числом ядер. Регрессия появилась в сборках разработки 26.7, когда учет памяти при агрегации стал точным. #114691 (alexey-milovidov).
  • Ускорены оконные функции на партиционированных таблицах MergeTree: каждая партиция читается в отдельном потоке, а окна вычисляются по каждой партиции без хеш-распределения, которое обычно перераспределяет все строки между потоками перед сортировкой окна. Оптимизация применяется, когда выражение партиционирования таблицы является детерминированной функцией от столбцов PARTITION BY окна, и регулируется той же эвристикой стоимости, что и GROUP BY / DISTINCT по каждой партиции (достаточное число партиций относительно max_threads, отсутствие доминирующей партиции). Управляется новыми настройками allow_window_partitions_independently (включена по умолчанию), force_window_partitions_independently и max_number_of_partitions_for_independent_window. #114783 (nihalzp).
  • Ускорены агрегатные функции timeSeries*ToGrid: при вычислении бакета для каждого образца больше не используется деление Int128, а для последовательных образцов, попадающих в один бакет, поиск в хеш-таблице пропускается. #114889 (nikitamikhaylov).
  • Образцы в агрегатных функциях timeSeries*ToGrid теперь обрабатываются группами последовательных образцов, попадающих в один бакет сетки. Это ускоряет этап приема образцов в timeSeriesRateToGrid и связанных функциях в 1,2–2 раза на отсортированных временных рядах. #115041 (nikitamikhaylov).
  • Агрегация без ключей GROUP BY больше не размножает свой однострочный результат на max_threads потоков, поэтому у запросов, план которых продолжается после такой агрегации, конвейер становится значительно меньше (меньше процессоров нужно создавать, планировать и профилировать) без потери параллелизма. #115170 (nikitamikhaylov).
  • Ускорено выполнение мгновенных запросов PromQL: агрегатные функции timeSeries*ToGrid используют векторизованную классификацию образцов для сеток из одной точки, а timeSeriesIdToGroup заполняет столбец результата напрямую. #115267 (nikitamikhaylov).
  • JOIN, секция ON которого содержит несколько равенств, объединенных через OR, больше не материализует столбцы ключей правой стороны, не выбираемые запросом. #115465 (nickitat).
  • Ускорено построение хеш-таблицы для ANY, SEMI и ANTI JOIN, когда в правой части одни и те же ключи соединения повторяются многократно: JOIN больше не перечитывает настройку join_any_take_last_row из памяти для каждой строки правой части. #115820 (nickitat).
  • Ускорен GROUP BY без агрегатных функций по ключам String, FixedString и LowCardinality: запрос больше не перезаписывает неиспользуемое значение-заполнитель в хеш-таблицу для каждой строки — только для строк, добавляющих новый ключ. #115834 (nickitat).
  • Снижено использование памяти и сокращено время оптимизации плана запроса для агрегаций по ключам над большими литералами, полученными в результате свёртки констант. Ключ кэша статистики хеш-таблиц агрегации теперь хешируется непосредственно в процессе сериализации, а не накапливается предварительно в памяти, поэтому план, содержащий большой литерал, больше не хранит его копию во время оптимизации. Для литерала размером 80 МБ пиковое потребление памяти снижается примерно на 250 МБ, а время оптимизации сокращается примерно в 2,5 раза. Вычисляемый ключ при этом не меняется. #115847 (groeneai).
  • Оптимизированы запросы GROUP BY ... ORDER BY ... LIMIT и GROUP BY ... LIMIT: во время агрегации поддерживается куча ограниченного размера, что позволяет отсекать группы, которые заведомо не попадут в результат. Это значительно снижает использование памяти и время выполнения при группировке по столбцам с высокой мощностью. Управляется настройкой enable_group_by_top_k_optimization. Основано на первоначальной реализации Dmitriy Terenichev #96630 (thevar1able).

Оптимизация и выполнение запросов

  • Чтение в порядке сортировки с параллельными репликами теперь использует ту же логику разбиения таблицы на max_threads частей, что и локальное чтение, что улучшает распараллеливание. #101434 (nickitat).
  • В модуль чтения Parquet добавлено пространственное отсечение GeoParquet на уровне групп строк и страниц. Отсечение на уровне групп строк пропускает целые группы строк, ограничивающий прямоугольник которых не пересекается с геометрией запроса. Отсечение на уровне страниц использует индекс столбца covering.bbox, чтобы пропускать нерелевантные страницы внутри групп строк. Кроме того, проталкивание пространственных предикатов обобщено через IFunctionBase::isSpatialPredicate(), а также добавлен GeoFilter, который вычисляет пространственные предикаты во время чтения строк Parquet. #104435 (bacek).
  • Добавлена настройка use_constant_folding_in_index_analysis (по умолчанию отключена). Если она включена, анализ первичного ключа MergeTree, MinMax и индексов пропуска подставляет константы уровня партиции в предикат фильтра отдельно для каждой части, что улучшает отсечение для фильтров, ветви которых зависят от значений партиции, например (a = 1 AND b >= 1) OR (a = 2 AND b > 10) при PARTITION BY a. #104582 (Michicosun).
  • Для запросов векторного поиска с vector_search_with_rescoring точное позиционирование строк теперь применяется до точного вычисления расстояний в конвейере запроса. #105591 (skuznetsov).
  • Добавлена оптимизация плана запроса, которая опускает функции, уменьшающие объём данных (length, lengthUTF8, empty, notEmpty), ниже шагов Sorting и Filter, заменяя широкий аргумент типа String / FixedString результатом фиксированного размера, благодаря чему он не буферизуется при сортировке и не копируется фильтром. Управляется новой настройкой query_plan_push_down_volume_reducing_functions, включённой по умолчанию. #106199 (fastio).
  • Ускорена загрузка кэша файловой системы при запуске: размер каждого файла кэша теперь кодируется в его имени (<offset>_<size>), что избавляет от вызова stat для каждого файла. Загрузка файлов кэша, записанных более старыми версиями, по-прежнему поддерживается. #107415 (alexey-milovidov).
  • Повышена производительность запросов полнотекстового поиска в сочетании с фильтром по первичному ключу. #108114 (CurtizJ).
  • Повышена производительность функции pointInPolygon с постоянным полигоном. Ключом кэша предварительно обработанных полигонов теперь служат исходные константные аргументы, поэтому постоянный полигон разбирается только один раз (при промахе кэша), а не заново для каждого входного блока. #108184 (groeneai).
  • Счётчики селективности system.predicate_statistics_log больше не обновляются на пути чтения MergeTree, когда эта функциональность отключена (predicate_statistics_sample_rate = 0, значение по умолчанию). Это убирает из каждого чтения атомарное обновление для каждой гранулы и подсчёт битов фильтра со сложностью O(rows), устраняя регрессию производительности, наиболее заметную на aarch64. #108190 (groeneai).
  • Добавлена настройка merge_use_batch_sorting_queueMergeTree, позволяющая использовать очередь пакетной сортировки для обычных слияний MergeTree. Это сокращает затраты CPU и общее время выполнения для нагрузок, где сортирующее слияние составляет значительную часть затрат. #108468 (rorylshanks).
  • Ускорено планирование запросов в анализаторе для выражений, которые многократно ссылаются на один и тот же псевдоним WITH или повторяют одно и то же подвыражение (например, глубоко вложенные цепочки if/multiIf): общие подвыражения больше не перестраиваются при построении DAG действий. #108523 (novikd).
  • Ускорен анализ запросов, содержащих много AND-цепочек сравнений или очень длинные такие цепочки: работа оптимизации optimize_and_compare_chain теперь ограничена бюджетом (новая настройка optimize_and_compare_chain_max_hash_work), и она больше не хеширует значительную часть дерева запроса, а при разрешении лямбда-выражений хеши тела лямбды больше не пересчитываются для защиты от рекурсии. #108757 (alexey-milovidov).
  • Постпроцессоры, выполняющие только фильтрацию (if(..., '', token)), теперь строят гранулу из исходных токенов и отбрасывают пустые значения на этапе построения. Это позволяет избежать материализации для каждого вхождения и выполнения ActionsDAG, характерных для общего пути. #109049 (ahmadov).
  • Устранено однопоточное узкое место в ShuffleSendStep распределённого плана запроса: каждый входящий поток теперь независимо распределяет свои строки по корзинам пункта назначения, а не пропускает весь фрагмент через один ScatterByPartitionTransform. #109206 (davenger).
  • Снижены накладные расходы CPU на вычисление выражений в запросах с большим количеством столбцов (например, при векторном поиске по столбцу QBit с малым шагом, когда каждый вектор разворачивается в сотни подстолбцов битовых плоскостей, которые передаются в один вызов *DistanceTransposed). #109380 (alexey-milovidov).
  • Фильтр теперь проталкивается ниже LIMIT BY, если предикат ссылается только на столбцы ключа LIMIT BY, а секция сохраняет хотя бы одну строку для каждой непустой группы (LIMIT n BY с n >= 1 и OFFSET 0). Благодаря этому такие предикаты (записанные как внешнее предложение WHERE вокруг подзапроса с LIMIT BY) доходят до хранилища и используются для отсечения по первичному ключу, индексов пропуска данных и проекций — вместо чтения всей таблицы и предварительного вычисления top-N для каждой группы. Семантика исключений для OFFSET, LIMIT 0 BY и отрицательных форм LIMIT BY при этом не меняется. #110116 (groeneai).
  • Устранено выделение памяти в куче при каждой проверке гиперпрямоугольника в ходе анализа индекса первичного ключа, что ускоряет фильтрацию засечек на 5–26% в зависимости от вида запроса. #110153 (raimannma).
  • Проталкивание фильтров в Parquet (отсечение групп строк и индексы столбцов) теперь поддерживает преобразования между вариантами DateTime64, вариантами Decimal, а также между Float32 и Float64. #110457 (al13n321).
  • Оптимизировано построение текстовых индексов пропуска данных и индексов на основе bloom-фильтра с токенизатором sparseGrams #110541 (UnamedRus).
  • При упорядочивании условий PREWHERE стоимость операций ввода-вывода теперь учитывается вместе с селективностью. Это устраняет регрессию производительности выполнения PREWHERE, возникавшую в некоторых случаях после https://github.com/ClickHouse/ClickHouse/pull/101275. Часть https://github.com/ClickHouse/ClickHouse/issues/110462 #110695 (Avogar).
  • Сокращено хеширование токенов, заданных в фильтре IN/NOT IN постпроцессора. #111690 (ahmadov).
  • Функции mapContainsKeyLike, mapContainsValueLike, mapExtractKeyLike и mapExtractValueLike с неконстантным шаблоном регулярного выражения потребляют меньше памяти и работают быстрее при включённой настройке enable_lazy_columns_replication. Шаблон больше не копируется заранее для каждой записи map в момент захвата: копирование откладывается до выполнения внутреннего лямбда-выражения, а память освобождается раньше, поэтому в пике в памяти находится на одну развёрнутую копию шаблона меньше. #111749 (diegomestre2).
  • По умолчанию включены (и переведены в статус бета) две функции, связанные с хранением данных на диске: 1) packed_skip_index_max_bytes = '1M': подпотоки индексов пропуска размером до 1 МиБ теперь записываются в единый архив skp_idx.packed для каждой части, что сокращает количество объектов и запросов на запись в объектном хранилище. Совместимость: изменение затрагивает только вновь записанные части, и они остаются полностью читаемыми в более старых версиях; версии до 26.6 просто не используют упакованные индексы для отсечения данных (они считаются нематериализованными). Чтобы сохранить прежнее размещение с отдельным файлом для каждого индекса, задайте packed_skip_index_max_bytes = 0. 2) compute_exact_num_defaults_for_sparse_columns вместе с optimize_trivial_count_with_sparsity_filter: точные счётчики num_defaults для каждого столбца сохраняются и используются для выполнения SELECT count() FROM t WHERE <pred> без сканирования данных, если предикат разделяет строки на значения по умолчанию и прочие. Совместимость: флаг exact_num_defaults в serialization.json игнорируется более старыми версиями, поэтому части остаются полностью читаемыми после понижения версии; переписывание count применяется только к частям с точными счётчиками, поэтому результаты остаются корректными и для таблиц со смешанными частями. #111816 (Algunenano).
  • Оптимизация транзитивных условий теперь использует свой дополнительный фильтр только для анализа индексов, если не может применить фильтр целиком. См. настройку optimize_and_compare_chain. #112076 (yariks5s).
  • API запросов Prometheus (/api/v1/query, /api/v1/query_range) экспериментального движка TimeSeries теперь выполняет запросы параллельно, а не в одном потоке. #112108 (nikitamikhaylov).
  • randomHadamardTransform от константного вектора теперь вычисляется один раз, а не для каждой строки. Это ускоряет запросы векторного поиска, которые поворачивают вектор запроса с помощью randomHadamardTransform перед сравнением со столбцом QBit. #112921 (alexey-milovidov).
  • Восстановлено совместное использование множеств задачами частей одной мутации, фильтрующей по IN (subquery) по столбцу первичного ключа. Настройка enable_sharing_sets_for_mutations включена по умолчанию, однако множество, построенное для анализа первичного ключа, перестало участвовать в общем кэше, из-за чего в таблице с N частями одно и то же множество материализовалось N раз. #112941 (groeneai).
  • В распределённых планах запросов (make_distributed_plan) ORDER BY ... LIMIT k теперь использует отложенную материализацию на каждой реплике: широкие столбцы читаются только для локальных top-k строк этой реплики, а не для всех строк-кандидатов. #113111 (shankar-iyer).
  • Ускорено планирование запросов при использовании статистики столбцов uniq_v2. Оценка количества уникальных значений теперь кэшируется, а не пересчитывается при каждом обращении — а при планировании одного запроса таких обращений происходит множество. #113357 (groeneai).
  • Проталкивание фильтров теперь работает для подстолбцов Tuple в файлах Parquet и ORC. Предикат вида WHERE tup.1 = 555555 для file(), s3() или url() теперь отсекает группы строк и шаги индекса строк по статистике самого элемента кортежа, а не читает файл целиком. #113383 (groeneai).
  • Повышена производительность запросов PromQL к движку TimeSeries: внутренний SQL селекторов теперь читает столбцы первичного ключа таблицы сэмплов напрямую (без холостых приведений типов) и проверяет диапазон временных меток до множества идентификаторов серий, благодаря чему «холодные» запросы с большим количеством селекторов выполняются на 30–44% быстрее. #113768 (nikitamikhaylov).
  • Селекторы PromQL, которые соответствуют всем сериям одной метрики, теперь при анализе индекса фильтруют таблицу сэмплов таблицы TimeSeries по непрерывному диапазону первичного ключа по id, а не по большому условию id IN <set>, если структура id представляет собой кортеж из двух компонентов с каноническим генератором id. Это устраняет основные затраты на однопоточный анализ индекса в PromQL-запросах с большим количеством селекторов: задержка при холодном запуске снижается до 45% для запросов дашбордов и правил, а среднее геометрическое холодной задержки на полном наборе тестов для таблицы с 62 миллиардами сэмплов — на 11%. #114131 (nikitamikhaylov).
  • Эндпоинты Prometheus HTTP API /api/v1/query и /api/v1/query_range теперь вычисляют подзапрос PromQL, общий для нескольких шагов плана, только один раз — так же, как это уже делали табличные функции prometheusQuery и prometheusQueryRange. Ранее запрос, выполненный с enable_analyzer = 0 или пользователем, в профиле которого задана эта настройка, повторно сканировал общий подзапрос для каждого ссылающегося на него шага. #114261 (groeneai).
  • Исправлена регрессия в 26.7: для таблицы MergeTree, упорядоченной по toUnixTimestamp (или другому целочисленному преобразованию) столбца DateTime64, простой фильтр по диапазону этого столбца перестал использовать первичный ключ и читал все гранулы подходящих частей. Кроме того, фильтр вида toInt64(ts) >= c по таблице, упорядоченной по исходному столбцу DateTime64, теперь использует первичный ключ. #114413 (alexey-milovidov).
  • Ускорено выполнение IN для кластеризованных столбцов (например, отсортированных по первичному ключу): для одинаковых идущих подряд строк повторно используется результат предыдущей строки. #114853 (nikitamikhaylov).
  • Устранена квадратичная сложность функций h3kRing, h3ToChildren, h3PolygonToCells и h3PolygonToCellsWithContainment при построении результата для большого числа строк. Во время стресс-теста в CI запрос по 196 000 строкам тратил 838 секунд на копирование памяти; теперь он выполняется примерно за 5 секунд. #115773 (groeneai).
  • Оптимизирован обратный поиск по словарю. Предикат равенства с константой, например WHERE dictGet(dict, attr, key_expr) = value, теперь при свёртке констант сразу преобразуется в фильтр по ключу (key_expr = const, key_expr IN [...] или WHERE 0), а не переписывается в подзапрос IN (SELECT ... FROM dictionary(...)); кроме того, ветка dictGetKeys для константных аргументов теперь выполняется параллельно. #91164 (nihalzp).
  • Добавлена новая настройка merge_tree_generic_exclusion_search_max_steps, ограничивающая число шагов, которые универсальный алгоритм поиска с исключением тратит на анализ индекса первичного ключа каждой части данных. Бюджет расходуется в первую очередь на самые большие из оставшихся диапазонов ключей, поэтому даже небольшой бюджет позволяет отсечь основной объём данных; не до конца проанализированные диапазоны читаются целиком, так что результаты запроса остаются корректными, но читаться может больше гранул. Ограничение нестрогое: оно может быть превышено не более чем на merge_tree_coarse_index_granularity шагов плюс по одному шагу на каждый диапазон, на которые часть уже разделена (например, кэшем условий запроса). Значение по умолчанию 0 означает отсутствие ограничения. #92779 (EmeraldShift).
  • Запросы с ORDER BY и LIMIT к VIEW поверх распределённых таблиц теперь используют оптимизацию слияния отсортированных потоков. Внешние ORDER BY/LIMIT проталкиваются во внутренний запрос простого представления, поэтому каждый шард сортирует свои данные локально, а координатор лишь сливает заранее отсортированные потоки, не выполняя полную сортировку у себя. #94102 (matanper).

Производительность хранилища, ввода-вывода и озер данных

  • Границы minmax-индекса партиций теперь используются для отсечения большего числа гранул при анализе первичного ключа в таблицах MergeTree, если столбец первичного ключа также входит в выражение ключа партиционирования. Например, в таблице MergeTree с ORDER BY (id, event_time) и PARTITION BY toYYYYMM(event_time) ClickHouse будет использовать minmax-индекс партиций по event_time при анализе индекса первичного ключа, чтобы точнее определять, какие гранулы можно отсечь. Управляется новой настройкой use_partition_minmax_for_primary_key_pruning (включена по умолчанию). #103480 (UnamedRus).
  • Ускорены операторы, которые сканируют отсортированный поток в поисках последовательностей одинаковых значений ключа: DISTINCT в порядке сортировки, LIMIT BY в порядке сортировки, отрицательный LIMIT BY в порядке сортировки, а также соединения full_sorting_merge и partial_merge. #106502 (nihalzp).
  • Ридер Parquet v3 теперь может пропускать целые группы строк по странице словаря (в дополнение к статистике min/max и bloom-фильтрам) для условий равенства и IN, если фрагмент столбца полностью закодирован словарём. Управляется новой настройкой input_format_parquet_dictionary_filter_push_down. #106952 (alexey-milovidov).
  • Для сжатия и декомпрессии gzip/zlib/deflate теперь используется libdeflate, что ускоряет работу (сжатие — примерно в 1,15 раза при лучшем коэффициенте, декомпрессия — примерно в 1,4–1,5 раза) для данных .gz/HTTP/url/s3 и кодека Parquet GZIP. #108074 (alexey-milovidov).
  • Ускорены функции trimLeft/trimRight/trimBoth с пробельными символами по умолчанию (и их псевдонимы ltrim/rtrim/trim): идущие подряд строки, не требующие обрезки, копируются одним пакетом, а построчный поиск пробелов выполняется только для строк, в которых действительно есть начальный или конечный пробел. #108177 (groeneai).
  • Ускорено чтение таблиц Iceberg за счёт предварительной загрузки следующего файла манифеста во время разбора текущего, что позволяет совмещать операции ввода-вывода с вычислениями на CPU. #108543 (asya-ch).
  • Запросы векторного поиска с пересчётом оценок теперь вычисляют точные расстояния только для строк-кандидатов, найденных векторным индексом, а не перебирают все соседние строки из той же гранулы MergeTree. #108846 (skuznetsov).
  • Добавлена настройка merge_tree_min_bytes_per_read_stream, позволяющая сократить избыточное число потоков чтения и накладные расходы конвейера при обычном локальном неупорядоченном сканировании узких столбцов MergeTree на серверах с большим числом ядер. #109035 (jiebinn).
  • Ускорены сериализация и слияния столбцов JSON, общие данные которых содержат множество разреженных путей. При развёртывании общих данных в отдельные столбцы для каждого пути flattenAndBucketSharedDataPaths больше не сканирует все накопленные столбцы путей для каждой строки и не вставляет значения по умолчанию по одной ячейке: построчное сканирование всех путей удалено, а пропуски заполняются массово. #109341 (groeneai).
  • Нативный протокол теперь передаёт столбцы String в виде отдельного потока накопленных байтовых смещений (та же структура, которую Array использует для своих смещений), за которым следуют конкатенированные данные, а не с префиксом длины varint для отдельных значений, — при условии, что обе стороны используют ревизию протокола 54489 или новее. Благодаря этому клиент может читать столбцы String с точным предварительным выделением буфера и одним массовым копированием — примерно в 4 раза быстрее, чем при структуре для отдельных значений. Старых клиентов и серверов это не затрагивает: структура согласовывается через ревизию протокола. Та же структура доступна в форматах Native и Buffers через новые настройки output_format_native_write_string_with_size_stream / input_format_native_read_string_with_size_stream (по умолчанию отключены, чтобы форматы оставались переносимыми). #110320 (vahid-sohrabloo).
  • Запросы с FINAL, читающие данные в порядке первичного ключа (ORDER BY по префиксу ключа сортировки) с небольшим LIMIT, больше не используют split_intersecting_parts_ranges_into_layers_final. #110431 (KochetovNicolai).
  • Отложенная (поздняя) материализация при чтении файлов Parquet из объектного хранилища, включая таблицы Iceberg: в запросах ORDER BY ... LIMIT n столбцы, не нужные для сортировки и фильтрации, читаются только для n строк, оставшихся после LIMIT. Для файла Parquet размером 200 МБ в S3 запрос SELECT k, s ... ORDER BY k DESC LIMIT 10 читает 3,3 МБ вместо 171 МБ (в 51 раз меньше IO, в 8 раз быстрее). Управляется новой настройкой query_plan_optimize_lazy_materialization_for_object_storage (включена по умолчанию; также требуется query_plan_optimize_lazy_materialization). #110970 (alexey-milovidov).
  • Запросы к таблицам Iceberg с большим количеством файлов удаления теперь запускаются быстрее. ClickHouse читает и декодирует манифесты удаления параллельно, а не по одному, благодаря чему операции чтения из хранилища выполняются одновременно. Новая настройка iceberg_delete_manifest_decode_concurrency (по умолчанию 4) задаёт, сколько манифестов декодируется одновременно. #112679 (asya-ch).
  • Добавлена опциональная сериализация UInt128/UInt256/Int128/Int256 в Parquet как DECIMAL, что позволяет отсекать группы строк и страницы. #113347 (bobrik).
  • Исправлено многократное дублирование запросов на чтение с удалённых дисков в случаях, когда один из шагов цепочки читателей читает фрагментированные диапазоны засечек, например диапазоны, отфильтрованные первичным индексом или индексами пропуска. #113584 (CurtizJ).
  • При записи кусков MergeTree, все ключи сортировки которых константны, больше не выполняется избыточная проверка отсортированности. #113899 (perfloop-agent).
  • Отложенная материализация для запросов ORDER BY ... LIMIT n теперь применяется и к локальным файлам Parquet, читаемым табличной функцией file и движком таблиц File: столбцы, не нужные для сортировки и фильтрации, читаются только для n строк, оставшихся после LIMIT. Если файл был изменён между двумя проходами, повторное чтение безопасно завершается с новой ошибкой FILE_CHANGED_DURING_READ. Управляется новой настройкой query_plan_optimize_lazy_materialization_for_file (включена по умолчанию). Также исправлена ошибка Not found column or subcolumn ... in block при отложенной материализации для объектного хранилища, возникавшая, когда чтение запрошенного подстолбца (например, столбца JSON) откладывалось. #114262 (alexey-milovidov).
  • Ускорено построение множества для IN (subquery) на партиционированных таблицах MergeTree: строки каждой партиции теперь обрабатываются в рамках одного потока, а дедупликация выполняется в каждом потоке независимо, поэтому единственное преобразование заполнения множества, которое ранее последовательно хешировало каждую строку, получает только уникальные строки. Это работает, когда выражение партиционирования является детерминированной функцией от выходных столбцов подзапроса. Оптимизация не применяется, если в самой крупной партиции более чем вдвое больше строк, чем в средней; новая настройка force_creating_set_partitions_independently (по умолчанию отключена) позволяет обойти эту проверку. Управляется новой настройкой allow_creating_set_partitions_independently (по умолчанию включена). #114645 (nihalzp).
  • Ротированные нереплицируемые системные таблицы логов MergeTree без TTL теперь помечаются как table_readonly, чтобы избежать лишних фоновых операций. Настройка table_readonlyMergeTree теперь также отключает всю фоновую работу для обычной таблицы MergeTree — обычные слияния, слияния по TTL (DELETE/MOVE/повторное сжатие) и слияния с повторным сжатием, фоновые мутации и фоновые перемещения частей — и отклоняет изменяющие команды для партиций (ATTACH/MOVE/DROP/DROP DETACHED/FETCH/REPLACE PARTITION и MOVE PARTITION ... TO TABLE в эту таблицу) — в дополнение к вставкам, мутациям и OPTIMIZE, которые отклонялись и ранее. Поэтому таблица table_readonly с TTL, пока настройка включена, больше не удаляет данные с истёкшим сроком хранения и не освобождает занимаемое ими место. #95079 (matt-metivier).

Эффективность использования памяти и ресурсов

  • Снижено использование памяти командой UNLOCK SNAPSHOT: метаданные отдельных частей данных, которые не нужны при снятии блокировки, больше не загружаются. Это предотвращает нехватку памяти при работе со снимками, содержащими очень большое количество частей. #111849 (jkartseva).
  • Сокращено число операций выделения памяти при чтении метаданных резервной копии: каждая запись о файле теперь не копируется, а перемещается в хранящиеся в памяти отображения (map). #111718 (jkartseva).

Производительность функций, типов данных и форматов

  • Форматирование значений Decimal в текст стало значительно быстрее — до 190 раз для Decimal256 с большим масштабом и примерно в 1,6 раза для Decimal64. На процессорах с поддержкой AVX-512 IFMA преобразование 64-битных целых чисел в текст ускорено примерно в 1,4 раза. Также исправлено округление в toDecimalString, при котором терялся перенос из дробной части: toDecimalString(toDecimal64('9.995', 3), 2) возвращала 9.00, а теперь возвращает 10.00. #112457 (thevar1able).
  • Повышена производительность алгоритма JOIN partial_merge для ключей типа FixedString: теперь последовательности значений сравниваются за один раз, а не отдельным вызовом сравнения для каждого значения. #105737 (4ertus2).
  • В HashJoin теперь нативно поддерживаются ключи из одного не-Nullable строкового столбца типа LowCardinality. #107264 (nickitat).
  • Повышена производительность replaceAll и replaceRegexpAll, когда шаблон и замена состоят из одного символа (например, replaceRegexpAll(s, ' ', '_')). Такие замены больше не меняют байтовую структуру строк, поэтому столбец теперь копируется один раз, а совпадающие байты перезаписываются на месте — без цикла поиска для каждого совпадения. #108178 (groeneai).
  • Ускорен разбор канонического представления даты и времени YYYY-MM-DD hh:mm:ss в режиме best-effort (date_time_input_format = 'best_effort', cast_string_to_date_time_mode = 'best_effort'), который используется по умолчанию. Это устраняет регрессию производительности разбора, возникшую после смены значений по умолчанию с basic на best_effort. #108187 (groeneai).
  • Разбор глубоко вложенных литералов массивов и кортежей теперь выполняется за линейное, а не за квадратичное время. #108892 (alexey-milovidov).
  • Функция toStartOfInterval (псевдонимы time_bucket, date_bin) ускорена до 5 раз для интервалов SECOND, MINUTE и HOUR. #109729 (raimannma).
  • Функции arraySort и arrayReverseSort при вызове без лямбда-выражения работают в несколько раз быстрее с числовыми массивами (включая Decimal и DateTime64). #109832 (raimannma).
  • Ускорены addDays, addWeeks, subtractDays и subtractWeeks для значений DateTime и DateTime64 в часовых поясах с фиксированным смещением (например, UTC) за счёт быстрого арифметического пути. #109836 (raimannma).
  • Декомпрессия кодека Delta векторизована. Декодирование теперь выполняется в 1,5–5 раз быстрее для 8/16/32-битных типов данных, а сканирование столбцов, сжатых с помощью Delta, — до 20% быстрее. #110189 (raimannma).
  • Ускорены функции поиска в строках (like, position, match, countSubstrings, hasToken и др.) по столбцам Enum с константной искомой строкой: теперь поиск выполняется не по каждой строке, а только по уникальным именам значений enum, после чего результаты сопоставляются с каждой строкой. #110325 (alexey-milovidov).
  • Производительность функций поиска подстрок (position, countSubstrings, multiSearch*, replaceAll/replaceOne, а также их регистронезависимых вариантов и вариантов для UTF-8) с непостоянным аргументом needle выросла до 1,5 раза: теперь при построчной обработке вместо наивного резервного варианта используются алгоритмы поиска строк на основе SIMD. #110580 (Algunenano).
  • Улучшена производительность объединения блоков (squashing) и слияния столбцов Dynamic и Object с большим количеством динамических вариантов или JSON-путей. #110583 (cv4g).
  • Ускорена работа estimateCompressionRatio с кодеком NONE #111107 (rienath).
  • Ускорены сортировка и другие операции на основе сравнения для JSON-столбцов, пути которых хранятся в общих данных. Ранее при каждом сравнении значений создавался временный столбец Dynamic и выполнялась полная двоичная десериализация обоих операндов, из-за чего ORDER BY по таким столбцам работал крайне медленно. #111894 (groeneai).
  • При делении 256-битных целых чисел (Int256, UInt256 и Decimal256) частное теперь вычисляется не побитово, делением столбиком методом сдвига и вычитания, а по одному 64-битному разряду (limb) за шаг: с помощью цикла делений 128 / 64, если делитель помещается в 64 бита, и с помощью алгоритма D Кнута в остальных случаях. Это затрагивает intDiv, modulo, арифметику Decimal256 и преобразование этих типов в текст. #112477 (thevar1able).
  • При чтении столбца Nested из типа в двоичной кодировке (Native, RowBinary с input_format_binary_decode_types_in_binary_format) тип больше не преобразуется обратно в имя типа с последующим повторным разбором. Кроме того, для некорректного имени вложенного типа Tuple теперь сразу выдаётся синтаксическая ошибка — вместо разбора, время которого росло экспоненциально с глубиной вложенности и завершалось ошибкой TOO_SLOW_PARSING. #112560 (alexey-milovidov).
  • Ускорены запросы PromQL к таблицам TimeSeries: если у последовательных строк совпадает id серии, timeSeriesIdToGroup теперь повторно использует группу предыдущей строки, не выполняя построчную сериализацию id и поиск в хеш-таблице. #113580 (nikitamikhaylov).

Другие улучшения производительности

  • Реализованы нативные средства чтения и записи для форматов Arrow и ArrowStream, не использующие библиотеку Apache Arrow, что позволяет избежать лишних копирований и преобразований данных. Теперь они используются по умолчанию (настройки input_format_arrow_use_native_reader и output_format_arrow_use_native_writer) и работают быстрее как при чтении, так и при записи. #106522 (alexey-milovidov).
  • Оптимизированы предикаты вида nullIf(key, sentinel) = const: теперь для них строятся диапазоны ключей, что позволяет выполнять отсечение по первичному ключу, партициям и индексам пропуска данных. #107308 (adityaksolves).
  • Производительность `INTERSECT ALL` и `EXCEPT ALL` (режим по умолчанию для `INTERSECT` и `EXCEPT`) выросла в несколько раз: ключом мультимножества теперь служит само значение строки, а не хеш SipHash каждой строки. #107649 (Algunenano).
  • Ускорены функции match, extract, extractAll, replaceRegexpOne и replaceRegexpAll для простых регулярных выражений за счёт их компиляции в нативный код с помощью LLVM. Поведение управляется новой настройкой compile_regular_expressions (включена по умолчанию); шаблоны, выходящие за рамки поддерживаемого подмножества, незаметно для пользователя обрабатываются движком RE2. #108004 (alexey-milovidov).
  • Ускорена декомпрессия ZSTD на AArch64 (ARM) для столбцов с малыми смещениями совпадений, например целочисленных столбцов фиксированной ширины, за счёт векторизации перекрывающихся копирований с коротким смещением с помощью NEON. Так, декомпрессия столбца UInt64 на AWS Graviton 4 выполняется до ~2,3 раза быстрее. #108049 (alexey-milovidov).
  • Повышена скорость декомпрессии LZ4 для столбцов фиксированного размера с низкой мощностью. #108175 (nickitat).
  • Повышена производительность levenshteinDistance (и editDistance) для строк средней длины на ARM за счёт отказа от выделения памяти в куче для каждой строки в блочной реализации алгоритма Майерса. #108185 (groeneai).
  • Ускорен разбор чисел с плавающей запятой из текста при precise_float_parsing = 1: теперь почти на всех входных данных он работает не медленнее парсера по умолчанию. Кроме того, встроенная библиотека fast_float обновлена до версии v8.2.10. #108205 (Algunenano).
  • Функции кодирования и декодирования Base64 теперь используют simdutf, что повышает их производительность. #108333 (thevar1able).
  • Оптимизирован DISTINCT для ресурсоёмких ключей с высокой мощностью. #108366 (nihalzp).
  • Повышена производительность математических функций за счёт включения оптимизаций компилятора, не сохраняющих errno. #108628 (nickitat).
  • Ускорена функция estimateCompressionRatio для столбцов с кодированием T64: сжатый размер теперь вычисляется аналитически, без фактического сжатия. #109054 (rienath).
  • JOIN теперь может использовать индекс первичного ключа или индекс пропуска данных левой таблицы для отсечения гранул #109085 (shankar-iyer).
  • Повышена производительность геофункций H3 (h3ToGeoBoundary, h3ToGeo, h3CellAreaM2/h3CellAreaRads2, geoToH3): синус и косинус теперь вычисляются совместно, а избыточные тригонометрические вызовы при преобразовании координат устранены. Результаты не изменились (побитово идентичны). #109399 (alexey-milovidov).
  • Сравнения (<, >, <=, >=) широких целочисленных типов (Int128, UInt128, Int256, UInt256 и основанных на них типов, например Decimal128) ускорены до 7 раз, а преобразование знаковых целых чисел в Int256 — до 7 раз на данных со смешанными знаками. Это достигнуто за счёт устранения ветвлений в коде сравнения и знакового расширения. #109474 (raimannma).
  • Функции с единственным неконстантным аргументом типа Nullable теперь используют null map аргумента совместно с результатом, а не выделяют память под новую карту с последующим слиянием. #110151 (raimannma).
  • Функции arrayMin и arrayMax для числовых массивов ускорены примерно в 1,3–1,5 раза благодаря векторизованной редукции вместо поэлементного цикла сравнения. #110163 (raimannma).
  • Повышена производительность DISTINCT в случаях, когда входной поток отсортирован по префиксу столбцов DISTINCT, например SELECT DISTINCT a, b FROM table ORDER BY a. Такие запросы выполняются до 2,4 раза быстрее. #110170 (nihalzp).
  • Добавлена векторизованная пакетная обработка для groupBitOr/groupBitAnd/groupBitXor и семейства функций дисперсии (varPop, varSamp, stddevPop, stddevSamp, skewPop, skewSamp, kurtPop, kurtSamp, covarPop, covarSamp, corr): ускорение до 4 раз с комбинатором -If при непредсказуемых условиях и до 3 раз для семейства функций дисперсии без него. #110461 (raimannma).
  • Оптимизирован анализ текстового индекса. #110530 (CurtizJ).
  • Ускорен разбор значений UUID из текста (например, JSONExtract в LowCardinality(UUID), toUUID, CAST AS UUID): проверка и преобразование шестнадцатеричных цифр теперь выполняются за один проход вместо двух. #110625 (groeneai).
  • Ускорена декомпрессия ZSTD на x86_64 для столбцов с небольшими смещениями совпадений (например, целочисленных столбцов фиксированной ширины) за счёт векторизации перекрывающихся копирований с короткими смещениями с помощью SSSE3 pshufb (аналог для x86_64 оптимизации AArch64 NEON из #108049). #110909 (thevar1able).
  • Функция groupUniqArray для числовых типов ускорена до 3 раз за счёт хеширования CRC32 (как в uniqExact) и встраивания построчной вставки. #110917 (raimannma).
  • Повышена эффективность minmax и базовой статистики столбцов для столбцов с плавающей запятой. #111221 (cv4g).
  • Запросы COUNT() теперь выполняются напрямую по метаданным мощности текстового индекса. #111494 (ahmadov).
  • Ускорены функции min и max для 128- и 256-битных типов (Int128, UInt128, Int256, UInt256, Decimal128, Decimal256): до 1,8 раза быстрее для широких целых чисел и до 3,4 раза быстрее для широких десятичных чисел. #111965 (raimannma).
  • Исправлено снижение производительности при записи в system.query_log. Построение столбцов типа Map Settings и asynchronous_read_counters выполнялось примерно в 6 раз медленнее, чем раньше, из-за чего SYSTEM FLUSH LOGS query_log мог превышать тайм-аут в 180 секунд на серверах, которые логируют много запросов с большим количеством изменённых настроек. #112210 (groeneai).
  • Добавлено необязательное кэширование токенов, отсутствующих в текстовых индексах. #112742 (rorylshanks).
  • Асинхронное логирование теперь использует ограниченную очередь без блокировок: потоки, записывающие сообщения лога, никогда не блокируются на мьютексе и не пробуждают потоки логирования. #112803 (alexey-milovidov).
  • Индекс первичного ключа теперь используется для pointInPolygon, если аргумент-точка представляет собой целый столбец ключа типа Point (или другой Tuple из двух числовых элементов), например pointInPolygon(coord, [...]) для таблицы, упорядоченной по coord. Ранее анализировалась только форма pointInPolygon((x, y), [...]) с двумя скалярными столбцами ключа. #112956 (alexey-milovidov).
  • Значение text_index_posting_list_apply_mode по умолчанию теперь lazy: запросы к текстовому индексу декодируют списки вхождений по требованию с помощью курсора с гранулярностью упакованных блоков, а не материализуют их заранее в битовые карты для текстовых индексов с заданным posting_list_codec. #113521 (CurtizJ).
  • Ускорены векторизованные преобразования тегов TimeSeries: переназначение на основе хеширования заменено прямой индексацией, если ID групп тегов занимают компактный диапазон. #114244 (fallintoplace).
  • Повышена производительность слияний текстовых индексов. #114525 (CurtizJ).
  • Для операторов над множествами в PromQL теперь используются компактные маски присутствия. #115224 (fallintoplace).
  • При подключении системных таблиц метаданные каждой таблицы, включая полное описание столбцов, больше не копируются дважды лишь для того, чтобы задать комментарий к таблице. #115490 (thevar1able).
  • Ускорены проверки на дублирование серий для полностью нулевых векторов условий PromQL. #115822 (fallintoplace).
  • Ускорены toUTCTimestamp/to_utc_timestamp и fromUTCTimestamp/from_utc_timestamp для аргументов DateTime64: восстановлена пропускная способность, утраченная после прежних исправлений переполнения. Результаты не изменились. #115838 (groeneai).
  • Снижены фиксированные накладные расходы на подготовку к генерации случайных данных (rand, rand64, randomString, randomFixedString, generateUUIDv4, generateUUIDv7) на x86-64. Эффект заметен при небольших блоках; генерируемые значения не изменились. #116158 (Algunenano).
  • Теперь с помощью настройки enable_function_early_short_circuit можно включить раннее свёртывание встроенных функций and и or по принципу сокращённого вычисления на этапе анализа. Это позволяет пропускать выполнение «мёртвых» однострочных скалярных подзапросов count(), сохраняя при этом обычный вывод типов и семантическую проверку. #83505 (fhw12345).
  • Для тривиально сериализуемых векторов теперь выполняется один вызов IO для буфера. #89842 (Ergus).
  • Настройка optimize_or_like_chain теперь включена по умолчанию. #94517 (alexey-milovidov).
  • Ускорено получение записи отдельного пользователя из system.users, когда на сервере много пользователей. #96699 (alistairjevans).

Улучшения

Улучшения запросов и SQL

  • Materialized CTE, на которые ссылаются несколько ветвей запроса UNION, теперь материализуются один раз и используются всеми ветвями совместно. Ранее каждая ветвь получала собственную копию CTE, которая встраивалась и вычислялась отдельно. #102107 (novikd).
  • JOIN runtime filter не применяется, если зондирующая (probe) сторона, по оценке, невелика. Порог задаётся новой настройкой join_runtime_filter_min_probe_rows (по умолчанию 1000) #104860 (vdimir).
  • Режим EXPLAIN [PLAN] actions=1, compact=1, pretty=1 теперь используется по умолчанию. #105036 (Fgrtue).
  • Уменьшена задержка отмены для положительных форм LIMIT BY (LimitByTransform, LimitBySortedStreamTransform): KILL QUERY и Ctrl+C теперь прерывают обработку в пределах одного чанка, не дожидаясь завершения всего шага. #106070 (rvasin).
  • Добавлена поддержка запросов с JOIN при автоматическом использовании параллельных реплик. #106073 (nickitat).
  • Добавлена новая асинхронная метрика UntrackedMemory (доступна в system.asynchronous_metrics), которая показывает объём памяти, уже выделенной потоками, но ещё не учтённой в глобальном счётчике отслеживания памяти. Каждый поток накапливает небольшие выделения локально и передаёт сведения о них пакетами. Это помогает объяснить расхождения между MemoryTracking и фактическим потреблением памяти процессом. Сообщения об ошибке MEMORY_LIMIT_EXCEEDED теперь также содержат объём неучтённой памяти, что помогает понять, почему запрос или сервер упёрся в лимит памяти. #106386 (mstetsyuk).
  • Если INSERT завершается ошибкой из-за того, что целевая таблица TO materialized view отклоняет запись на этапе построения конвейера вставки (например, если целевой объект является View или не поддерживает транзакции), в сообщении об ошибке теперь указываются materialized view и её целевая таблица, а не только исходная ошибка хранилища. #107234 (groeneai).
  • ALTER TABLE ... MODIFY COLUMN <col> Tuple(...) для именованного Tuple теперь изменяет только метаданные, если добавляются лишь подполя, и выполняется так же быстро, как ADD COLUMN верхнего уровня. Включается с помощью SET allow_metadata_only_named_tuple_alter = 1. #107305 (amosbird).
  • Для движка баз данных MaterializedPostgreSQL добавлена настройка materialized_postgresql_use_extended_date_and_time_types, задаваемая при создании базы данных. По умолчанию (настройка включена) для столбцов PostgreSQL date/timestamp выводятся типы Date32/DateTime64; если при CREATE DATABASE задать значение 0, будут выводиться более узкие типы Date/DateTime. Настройка неприменима к движку таблиц MaterializedPostgreSQL. #107428 (alexey-milovidov).
  • EXPLAIN PLAN теперь помечает оценку числа строк результата JOIN как приблизительную (~~...), если она получена из подсказки или случайного резервного значения, а не из статистики таблицы. Это помогает выявлять планы, для которых нет надёжной статистики для переупорядочивания JOIN. #107666 (vdimir).
  • INSERT в таблицу MergeTree теперь учитывает отмену запроса и max_execution_time при записи большого количества кусков и больше не продолжает выполняться долгое время после принудительного завершения. #107929 (al13n321).
  • arrayFold теперь учитывает отмену запроса и max_execution_time. Ранее свёртка очень длинного массива (например, arrayFold(acc, x -> arrayPushFront(acc, x), range(number), emptyArrayUInt64())) целиком выполнялась внутри одного вызова функции и не могла быть прервана, поэтому KILL QUERY и ограничения по времени игнорировались до завершения свёртки. #108192 (groeneai).
  • Добавлены ProfileEvents для отдельных этапов подготовки запроса к выполнению: QueryParseMicroseconds, QueryAnalysisMicroseconds, QueryPlanBuildMicroseconds и QueryPipelineBuildMicroseconds. Они показывают, на что уходит время до выполнения запроса (разбор, анализ, построение плана запроса, построение конвейера), и доступны в system.query_log и system.events. #108282 (jrdi).
  • Операции ALTER TABLE, в результате которых метаданные таблицы превысили бы max_query_size, теперь отклоняются заранее. Это не позволяет таблицам оказаться в состоянии, когда их не могут загрузить такие компоненты, как распространение DDL и восстановление реплик. #108283 (lockie).
  • Добавлен ConstantJoin для декартовых JOIN и JOIN с константными предикатами, планируемых анализатором, поэтому такие запросы больше не завершаются ошибкой из-за несовместимого значения настройки join_algorithm при использовании анализатора. #108289 (antaljanosbenjamin).
  • В system.documentation добавлен столбец source, содержащий путь к исходному файлу, в котором определена документация каждой сущности. Теперь таблица также документирует кодеки сжатия, события профилирования, текущие метрики, асинхронные метрики и сами системные таблицы (вместе с их столбцами), а в документацию настроек добавлены их тип и значение по умолчанию. #108346 (alexey-milovidov).
  • Если в предложении WHERE указаны фильтры по table и database, то system.iceberg_history выведет только соответствующие им базы данных. Это может сэкономить время, если на сервере много посторонних удалённых баз данных. #108492 (Diskein).
  • Параметры запроса (подстановки {name:Type}) теперь можно использовать в качестве значений настроек — как в предложении SETTINGS запроса (например, SELECT или INSERT), так и в отдельных запросах SET, например SELECT ... SETTINGS max_threads = {threads:UInt64} и SET max_threads = {threads:UInt64}. #108760 (alexey-milovidov).
  • Добавлена возможность вычислять совокупный выигрыш от индексов пропуска в EXPLAIN WHATIF. Выводится доля данных, представляющая собой пересечение эффекта всех подходящих гипотетических индексов. #108934 (yariks5s).
  • Запрос с одним CTE теперь форматируется с теми же переносами строк и отступами, что и запрос с несколькими CTE. Ранее в WITH a AS (...) CTE оставался на одной строке с WITH, тогда как при двух и более CTE WITH выносился на отдельную строку, а каждый CTE выводился с отступом. #109092 (groeneai).
  • Добавлена поддержка кэша условий запроса для локальных файлов Parquet, читаемых через табличный движок File (ранее она была доступна только для объектного хранилища и озёр данных). #109247 (alexey-milovidov).
  • Ключ кэша условий запроса для удалённых файлов Parquet (в объектном хранилище) теперь включает ETag в дополнение к пути, поэтому перезапись объекта на месте больше не приводит к выдаче устаревших результатов из кэша. #109310 (alexey-milovidov).
  • Неквалифицированная ссылка на ключ INNER JOIN, приравниваемый в условии ON (например, SELECT id FROM a INNER JOIN b ON a.id = b.id), больше не считается неоднозначным идентификатором, поскольку обе стороны гарантированно содержат одно и то же значение. #109366 (alexey-milovidov).
  • Транспонированные функции расстояния для QBit (L2DistanceTransposed, cosineDistanceTransposed, dotProductTransposed и их квантованные аналоги L2DistanceTransposedQuantized, cosineDistanceTransposedQuantized, dotProductTransposedQuantized) теперь принимают опорный вектор, длина которого превышает число размерностей, по которым выполняется поиск; лишние конечные элементы при этом игнорируются. Это позволяет повторно использовать полноразмерный вектор запроса для поиска с уменьшенной размерностью (Matryoshka), не обрезая его предварительно. #109388 (alexey-milovidov).
  • Добавлена проверка того, что распределённый запрос всегда содержит известную версию клиента: вместо того чтобы молча передавать удалённым шардам нулевую версию, выбрасывается логическая ошибка. Запросы, инициированные сервером (фоновые сбросы на диск, потребители стриминга, перезагрузка словарей, сброс асинхронных вставок), теперь передают в качестве версии инициатора собственную версию сервера. #109408 (alexey-milovidov).
  • Исправлено использование квалифицированных имён столбцов в предложении WHERE операции мутации для движков таблиц семейства MergeTree. #109491 (Michicosun).
  • Добавлена поддержка оконных функций без партиционирования (OVER (ORDER BY ...)) в распределённых планах запросов (make_distributed_plan). Ранее любой запрос с оконной функцией завершался ошибкой, поскольку WindowStep невозможно было сериализовать для удалённого выполнения; окна с PARTITION BY пока по-прежнему не поддерживаются. #109802 (VighneshPath).
  • Теперь некоторые настройки аутентификации каталога one-lake можно изменить с помощью ALTER DATABASE ... MODIFY SETTING = 'xxx'. #110019 (alesapin).
  • Подзапрос в правой части IN, единственный столбец которого является массивом с размерностью на единицу больше, чем у левого аргумента, теперь интерпретируется как множество элементов массива (аналогично литералу массива или функции, возвращающей массив), а не завершается непонятной ошибкой несоответствия типов. Например, теперь работает x IN (SELECT groupArray(x) FROM ...). #110169 (alexey-milovidov).
  • Запросы, ускоренные динамической фильтрацией TopK (ORDER BY ... LIMIT k), теперь полнее используют кэш условий запроса: кэш заполняется даже при применении ленивой материализации, а такие запросы могут повторно использовать записи, ранее созданные обычным запросом с тем же предикатом WHERE. #110507 (shankar-iyer).
  • Если запрошенная таблица не существует, SHOW CREATE TABLE (а также SHOW CREATE VIEW / SHOW CREATE DICTIONARY) теперь предлагает в сообщении об ошибке таблицу с похожим именем — так же, как это делают запросы SELECT. #110633 (alexey-milovidov).
  • Добавлен модификатор STREAM BOUNDED, при использовании которого потоковый запрос считывает только первый снимок данных и завершается, а не подписывается на обновления. #110653 (SmitaRKulkarni).
  • Исправлен кэш результатов запросов для запросов PromQL. Диалект promql обходил проверку недетерминированных функций и мог возвращать устаревшие результаты, привязанные к now(), а Prometheus HTTP API (/api/v1/query, /api/v1/query_range) вообще не сохранял записи в кэш. #110887 (nikitamikhaylov).
  • EXPLAIN ANALYZE теперь выводит количество строк с каждой стороны соединения, долю совпадений, коэффициент размножения строк (fanout), а также состояние, специфичное для алгоритма, например объём памяти хеш-таблицы и сброс данных на диск. Чтобы собирать метрики совпадений, требующие дополнительного учёта, используйте matches = 1. #110892 (Fgrtue).
  • Исправлена ошибка heap-use-after-free в исполнителе конвейера, которая могла приводить к аварийному завершению сервера, если запрос удалял процессоры во время выполнения (например, FINAL с ленивым чтением или внешней сортировкой). Ошибка обнаружена AST-фаззером. #111017 (groeneai).
  • Исправлена ошибка use-after-free (ошибка сегментации), возникавшая, когда запрос с общим снимком хранилища (настройка enable_shared_storage_snapshot_in_query) удалял части данных из снимка — например, если потоковый подзапрос читал ту же таблицу MergeTree, которую одновременно читала другая часть запроса. #111192 (alexey-milovidov).
  • Добавлена поддержка распределённых планов запросов (make_distributed_plan) для запросов, источник которых уже на этапе планирования заведомо не возвращает строк, например при чтении из пустой таблицы MergeTree. Ранее такие запросы завершались ошибкой SUPPORT_IS_DISABLED. #111941 (groeneai).
  • Исправлена ошибка, из-за которой кэш условий запроса не заполнялся для гранул, отсеянных любым конъюнктом, кроме последнего, в предложении WHERE с несколькими условиями AND. #112083 (shankar-iyer).
  • Снижено пиковое потребление памяти при записи JSON-столбцов с бакетной сериализацией общих данных (map_with_buckets и advanced): теперь при записи общие данные разбиваются на бакеты поочерёдно, а не материализуются все бакеты одновременно. Наибольший выигрыш это даёт для столбцов Array(JSON). Для скалярного JSON общие данные разбиваются по гранулам (с ограничением index_granularity_bytes), поэтому экономия невелика, тогда как одна гранула Array(JSON) может содержать множество вложенных строк и, соответственно, большой объём общих данных — здесь поочерёдное разбиение по бакетам заметно снижает пиковое потребление памяти #112172 (Avogar).
  • Планирование резервирования памяти (экспериментальная функция) больше не вытесняет выделение памяти, если ожидаемое освобождение памяти обеспечит место, необходимое для увеличения резервирования сверх лимита: решение о вытеснении теперь принимается только после применения уже выполняющихся уменьшений. Это позволяет избежать лишнего завершения запросов при нехватке памяти. #112299 (serxa).
  • SYSTEM DROP FILESYSTEM CACHE теперь удаляет ключи метаданных кэша параллельно, что ускоряет очистку большого файлового кэша. Новая настройка файлового кэша drop_cache_threads задаёт число обработчиков удаления (по умолчанию 16); при значении 1 удаление выполняется в потоке запроса. #112532 (kssenii).
  • Модификаторы объявления столбца — COMMENT, CODEC, STATISTICS, TTL, COLLATE, PRIMARY KEY и SETTINGS для отдельного столбца — теперь можно указывать в CREATE TABLE в любом порядке, причём каждый не более одного раза. Ранее допускался только один фиксированный порядок, и, например, x UInt64 CODEC(ZSTD) COMMENT 'text' приводило к синтаксической ошибке. В ALTER TABLE ... ADD COLUMN / MODIFY COLUMN поддерживаемые модификаторы — COMMENT, CODEC, STATISTICS, TTL и SETTINGS для отдельного столбца — также можно указывать в любом порядке. При этом SETTINGS для отдельного столбца в ADD COLUMN и объявленные STATISTICS в ADD COLUMN / MODIFY COLUMN теперь применяются, а не отбрасываются без предупреждения, а COLLATE и PRIMARY KEY в этих командах ALTER теперь приводят к исключению, а не игнорируются молча. #112788 (alexey-milovidov).
  • Запрос к таблице Merge (или к табличной функции merge), охватывающий множество таблиц, теперь реагирует на KILL QUERY и max_execution_time ещё во время построения планов запросов для отдельных таблиц, а не только после завершения планирования всех дочерних таблиц. #113415 (alexey-milovidov).
  • SELECT из таблицы Merge, превысивший max_execution_time при timeout_overflow_mode = 'break', теперь прекращает построение планов запросов для оставшихся подходящих таблиц, а не выполняет перед остановкой полный анализ запроса для каждой из них. Как и предусмотрено документацией этого режима, запрос по-прежнему завершается без ошибки. #113642 (groeneai).
  • Если при чтении из MergeTree объявленный тип столбца расходится с его данными (смешанное происхождение типов, например после ALTER TABLE ... MODIFY COLUMN, мутация которого ещё не завершилась), сервер теперь выдаёт понятное исключение с указанием столбца и обеих структур вместо непроверенного приведения типа. Ранее отладочные сборки и сборки с санитайзерами аварийно завершались с одним лишь сообщением Bad cast from type A to B без указания столбца, а релизные сборки молча обращались к памяти с несоответствующей структурой. #114087 (alexey-milovidov).
  • ie_join включён по умолчанию: значение join_algorithm по умолчанию теперь direct,parallel_hash,hash,ie_join. JOIN, секция ON которого содержит только условия неравенства (два сравнения <, <=, >, >= между выражениями соединяемых таблиц), теперь выполняется алгоритмом IEJoin на основе сортировки вместо CROSS JOIN с фильтром; также поддерживаются соединения LEFT/RIGHT/FULL/SEMI/ANTI с такими условиями. Поскольку ie_join стоит в списке последним, он используется только тогда, когда остальные алгоритмы неприменимы. #114327 (vdimir).
  • Контекст трассировки OpenTelemetry теперь передаётся в файберы, используемые для асинхронного установления соединений и удалённого выполнения запросов (hedged requests, async_socket_for_remote, async_query_sending_for_remote). Спаны удалённых запросов в распределённом запросе теперь корректно становятся дочерними по отношению к спану Connection::sendQuery инициатора, а не привязываются напрямую к контексту трассировки, переданному клиентом. Кроме того, каждое выполнение асинхронной задачи порождает собственный спан. #114813 (diegomestre2).
  • DROP DATABASE теперь удаляет таблицы в обратном топологическом порядке с учётом как зависимостей загрузки, так и ссылочных зависимостей (ранее учитывались только зависимости загрузки), поэтому сбой посреди выполнения DROP DATABASE уже не может оставить таблицу, зависимости которой уже удалены. #114952 (alexey-milovidov).
  • Добавлена поддержка операторов сопоставления с регулярным выражением в стиле PostgreSQL: ~ (псевдоним функции match), ~* (регистронезависимое сопоставление), !~ и !~* (отрицания). Команды \d, \dt, \dv утилиты psql теперь работают при подключении к ClickHouse по протоколу совместимости с PostgreSQL, а неудачный запрос больше не разрывает соединение. #115066 (alexey-milovidov).
  • EXPLAIN WHATIF теперь сообщает, почему эмпирическая оценка была пропущена: причина выводится в новой строке empirical_reason, если empirical_status имеет значение unsupported. #115140 (yariks5s).
  • Если ни один из алгоритмов JOIN, включённых настройкой join_algorithm, не может выполнить JOIN, сообщение об ошибке теперь перечисляет опробованные алгоритмы, а также строгость и тип JOIN, который не удалось выполнить, а не просто сообщает, что ни один из алгоритмов не сработал. #115226 (elkinal).
  • Запросы векторного поиска теперь могут использовать индекс векторного сходства, если опорный вектор задан литералом целочисленного массива, например ORDER BY L2Distance(vec, [1, 2]). Ранее такие запросы без предупреждения переходили к полному перебору. #115255 (rschu1ze).
  • BACKUP больше не оставляет файл блокировки в пункте назначения, если создавшая его попытка завершается неудачей до записи каких-либо данных — будь то при захвате пункта назначения или при открытии архива. Такую блокировку не могла подхватить ни одна последующая резервная копия, поэтому все повторные попытки в тот же пункт назначения завершались ошибкой, пока файл не удаляли вручную. Кроме того, при резервном копировании в пункты назначения S3 и Azure блокировка теперь создаётся эксклюзивно, а если блокировка принадлежит другой резервной копии, об этом сообщается как о параллельном резервном копировании, а не как о произвольной ошибке, возвращённой хранилищем. #115387 (jkartseva).
  • Трассировка, запущенная в результате сэмплирования (opentelemetry_start_trace_probability), теперь записывается обратно в клиентскую информацию запроса, поэтому удалённые и распределённые вторичные запросы, а также записи DDL присоединяются к той же трассировке, а не создают отдельные. #115619 (diegomestre2).
  • Исправлена работа CREATE TABLE для таблиц Iceberg на базе Amazon S3 Tables, где расположением таблиц управляет сам сервис. #115652 (scanhex12).
  • Адаптивная агрегация GROUP BY (enable_adaptive_aggregator) теперь оценивает, окупается ли откладывание редких ключей, и возвращается к обычному алгоритму, если ключи или аргументы агрегатных функций слишком широки, чтобы их копирование было выгодным. Благодаря этому агрегации по тяжёлым строковым столбцам (например, min(URL) для каждого пользователя) выполняются со скоростью и потреблением памяти обычного алгоритма. Добавлена настройка adaptive_aggregator_freeze_threshold_bytes, ограничивающая размер замороженной таблицы каждого потока в байтах (таблица замораживается при достижении любого из двух порогов — этого или порога по количеству ключей, — в зависимости от того, какой будет достигнут первым). #115755 (nihalzp).
  • Добавлена настройка query_plan_aggregation_bucket_top_k (включена по умолчанию), которая включает и отключает оптимизацию плана, материализующую только n лучших групп каждого двухуровневого бакета, когда результаты финальной агрегации передаются в ORDER BY по её выходным столбцам с LIMIT n. Эта оптимизация теперь также отображается в выводе EXPLAIN. #116124 (nihalzp).
  • Улучшена поддержка запроса DESCRIBE для параметризованных представлений. В новом анализаторе добавлена поддержка параметризованных представлений в скалярных выражениях. #68978 (novikd).
  • Запросы вида SELECT * FROM t WHERE id теперь используют индекс пропуска данных для столбца id. #89603 (adityachopra29).
  • Добавлена настройка query_plan_merge_expression_into_join, которая позволяет объединять шаги Expression с шагами JOIN при оптимизации переупорядочивания JOIN. Благодаря этому переупорядочивание JOIN становится возможным и для подзапросов, внутри которых находятся соединения (например, когда JOIN расположен в подзапросе с вычисляемыми столбцами), что улучшает оптимизацию сложных деревьев соединений. #98533 (vdimir).
  • В таблицу system.grants добавлен столбец is_wildcard, который показывает, использует ли привилегия сопоставление по префиксу с подстановочным шаблоном (например, GRANT SELECT ON db*.*). Ранее в system.grants нельзя было отличить привилегии с подстановочным шаблоном от точных привилегий с тем же именем. #98577 (il9ue).

Функции и типы данных

  • Добавлена новая настройка allow_lossy_numeric_supertype (по умолчанию отключена). Если она включена, if, multiIf, coalesce, ifNull, array и map над числовыми аргументами, у которых нет общего типа без потери точности (например, Decimal и Float64 или Int64 и Float64), приводятся к числовому супертипу Float64, а не к Variant, поэтому результат можно использовать с агрегатными функциями, такими как sum, avg, min и max. Имя настройки теперь упоминается в соответствующих сообщениях об ошибках агрегатных функций. #107236 (groeneai).
  • Квантор массива SOME / ALL (expr OP SOME(array) / expr OP ALL(array)) теперь также поддерживает предикаты сравнения на основе ключевых слов IS DISTINCT FROM и IS NOT DISTINCT FROM, а также предикаты поиска по строке LIKE, ILIKE, NOT LIKE, NOT ILIKE и REGEXP; такие выражения переписываются в arrayExists / arrayAll. #107454 (alexey-milovidov).
  • Добавлена настройка input_format_json_max_object_size для ограничения размера объекта JSON при разборе. #107669 (Avogar).
  • Исправлена утечка памяти, возникавшая при неудачной попытке открыть базу данных SQLite (например, когда табличной функции sqlite или движку баз данных SQLite передаётся путь, который невозможно открыть). #107807 (alexey-milovidov).
  • Добавлена поддержка функции length для типа данных QBit. Она возвращает размерность вектора в виде константы. #108071 (alexey-milovidov).
  • Добавлена поддержка CAST из QBit в Array с восстановлением исходного вектора. Это преобразование, обратное уже существующему преобразованию Array в QBit. #108072 (alexey-milovidov).
  • Движок баз данных, движок таблицы и табличная функция MySQL теперь сопоставляют пространственные типы столбцов MySQL (LINESTRING, POLYGON, MULTILINESTRING, MULTIPOLYGON и обобщённый GEOMETRY) с соответствующими геометрическими типами ClickHouse вместо String. Это поведение управляется новым флагом geometry настройки mysql_datatypes_support_level, который включён по умолчанию. POINT по-прежнему всегда преобразуется в Point. Обобщённый столбец GEOMETRY сопоставляется с объединяющим типом Geometry; при чтении значения, подтип которого не имеет аналога в ClickHouse (MULTIPOINT, GEOMETRYCOLLECTION), генерируется исключение. #108944 (alexey-milovidov).
  • Теперь по умолчанию используется точный алгоритм разбора чисел с плавающей точкой (с выбором ближайшего представимого значения), а настройка precise_float_parsing применяется к входным форматам (CSV, TSV, JSON, VALUES, …) и числовым литералам, а не только к toFloat*/CAST. Чтобы вернуть прежнее поведение — в некоторых случаях более быстрое, но менее точное, — установите precise_float_parsing = 0. #109086 (Algunenano).
  • Добавлена поддержка reinterpret массива Array из элементов фиксированного размера как String — операции, обратной уже существующему reinterpret значения String/FixedString как Array. #109383 (alexey-milovidov).
  • Разрешено выполнять CAST между типами QBit, которые различаются типом элементов и/или параметром stride, при условии что размерность остаётся прежней (например, CAST(x AS QBit(Float64, N)) из QBit(Float32, N)). Изменение только stride происходит без потерь; при изменении типа элементов действует та же семантика, что и при соответствующем преобразовании Array (например, при преобразовании Float32 в BFloat16 возможна потеря точности, а accurateCast / accurateCastOrNull отклоняют строки, которые невозможно представить точно). #109387 (alexey-milovidov).
  • Функции quantizeBFloat16ToInt8 и dequantizeInt8ToBFloat16 теперь, помимо существующих скалярных перегрузок, принимают аргументы типов Array и QBit, применяя кодек Ллойда — Макса ко всему вектору (и возвращая Array/QBit с соответствующим типом элементов). #109398 (alexey-milovidov).
  • Спецификатор формата %f в стиле MySQL в parseDateTime / parseDateTime64 (и их вариантах OrZero / OrNull) теперь принимает от 1 до 6 цифр дробной части вместо ровно 6; они интерпретируются как микросекунды с выравниванием по левому краю, как в STR_TO_DATE в MySQL. Также исправлено смещение таблиц PrettyCompact в примерах встроенной документации функций. #109421 (alexey-milovidov).
  • Подстатистика NullCount статистики basic переименована в DefaultCount: вместо подсчёта строк со значением NULL в столбце типа Nullable функция build теперь подсчитывает строки, равные собственному значению по умолчанию для типа столбца, с помощью IColumn::getNumberOfDefaultRows. #109977 (hanfei1991).
  • Размер исполняемого файла уменьшен примерно на 10,5 МБ: операции сравнения и арифметические операции над редко используемыми парами смешанных типов (Decimal и целое число другой разрядности, а также пары с участием Int128/UInt128/Int256/UInt256) теперь выполняются через преобразование к общему типу, а не с помощью отдельного скомпилированного ядра для каждой комбинации типов. Пары одинаковых типов, часто используемые пары, а также ограниченные пропускной способностью памяти plus/minus/multiply сохраняют свои отдельные ядра; результаты, типы результатов и обработка исключительных случаев не изменились. #110131 (alexey-milovidov).
  • Чтение из движка таблицы SQLite или табличной функции sqlite больше не загружает ядро CPU на 100 % активным ожиданием, когда база данных SQLite заблокирована другим соединением. Теперь во время ожидания блокировки чтение простаивает, и его по-прежнему можно отменить. #110248 (groeneai).
  • Значения затраченного времени, скорости и доли в журналах и сообщениях об исключениях теперь округляются до трёх цифр, поэтому числа вроде 1.345844286 sec. больше не выводятся с полной точностью. #110277 (alexey-milovidov).
  • Исправлено чтение в MergeTree столбцов типа String с отдельным потоком размеров после пропуска начальных строк: оно могло возвращать неверные данные или выходить за границы кеша подпотоков. Также исправлена возможная выдача неверных данных при параллельном или повторном чтении вложенного объекта JSON, хранящегося с сериализацией shared-data в виде map. #110471 (alexey-milovidov).
  • Добавлена поддержка предложения SETTINGS для движка таблицы PostgreSQL и табличной функции postgresql (например, SETTINGS postgresql_connection_pool_size = 50) — теперь их возможности соответствуют движку MySQL. #110614 (alexey-milovidov).
  • Функции bitmaskToArray и bitmaskToList теперь поддерживают аргументы (U)Int128 и (U)Int256. Для аргументов с большими целыми числами функция bitPositionsToArray теперь выполняется за время, пропорциональное количеству установленных битов, а не позиции старшего установленного бита. #110743 (raimannma).
  • Исправлена обработка кодеком GCD знаковых значений фиксированной ширины, содержащих отрицательные числа. Ранее делитель вычислялся непосредственно по знаковым значениям, из-за чего общий делитель мог не обнаруживаться, а эффективность сжатия для столбцов знаковых целочисленных и десятичных типов значительно снижалась. Теперь для знаковых типов делитель вычисляется по модулям значений, а поведение для беззнаковых типов и декомпрессии не изменилось. #113798 (kshcherbatov).
  • Оконная функция с PARTITION BY теперь работает при включённом make_distributed_plan. Если структура плана позволяет, окно вычисляется параллельно по бакетам, каждый из которых получает партиции целиком. #114111 (VighneshPath).
  • Для внешних методов агрегации по Nullable-ключам фиксированной ширины теперь используется 64-битная хеш-функция (это предотвращает лавину коллизий при агрегации с очень высокой мощностью). #114210 (nickitat).
  • x IN (subquery) для столбца LowCardinality теперь возвращает LowCardinality(UInt8) — тот же тип, что и x IN (literal list). Ранее эти две формы возвращали разные типы, и для распределённых планов с таким IN при проверке типов плана требовалась отдельная обработка. #114229 (davenger).
  • Добавлена поддержка разбора целых чисел, выходящих за пределы 64-битного диапазона, в типе данных JSON, а также в JSONExtract и isValidJSON. Такие значения считываются в широкие целочисленные типы, например Int128/UInt256, и больше не приводят к отклонению всего документа. #114379 (Avogar).
  • Добавлен псевдоним keyword для токенизатора текстового индекса array — для лучшей совместимости с OpenSearch, Elasticsearch, SolR и Lucene. #115507 (rschu1ze).
  • Функции toDateOrNull, toDateTimeOrNull и toDateTime64OrNull теперь принимают аргументы всех встроенных целочисленных типов (они интерпретируются так же, как в toDate, toDateTime и toDateTime64, с необязательным аргументом часового пояса) и возвращают NULL для значений, выходящих за пределы диапазона результирующего типа. Например, toDateTimeOrNull(1583851242, 'Asia/Shanghai') возвращает 2020-03-10 22:40:42, а toDateTimeOrNull(4294967296) — NULL. #79791 (jitendra1411).

Хранилище, озера данных и объектное хранилище

  • Добавлены опциональные метрики Prometheus для отслеживания вытеснения из кэша файловой системы (filesystem_cache_evictions_total, filesystem_cache_evicted_bytes_total, filesystem_cache_evicted_segment_hits, filesystem_cache_evicted_segment_size_bytes, а также их варианты для отдельных пользователей с меткой user_id). Метрики доступны для каждого кэша через system.dimensional_metrics, system.histogram_metrics и конечную точку Prometheus. Они управляются настройками конфигурации диска кэша expose_prometheus_eviction_metrics и expose_prometheus_eviction_metrics_per_user (обе по умолчанию отключены), которые можно переключать без перезапуска с помощью SYSTEM RELOAD CONFIG. #105020 (sacheendra).
  • Движок Alias теперь поддерживает чтение с параллельных реплик, если целевая таблица использует движок семейства MergeTree. #107830 (nauu).
  • Количество одновременно подготавливаемых частей при копировании в Azure Blob Storage по схеме «чтение, затем запись» (применяется при резервном копировании, когда нативное копирование недоступно) теперь ограничено значением max_inflight_parts_for_one_file. Это предотвращает чрезмерное использование памяти при параллельном копировании множества больших файлов. #108232 (SmitaRKulkarni).
  • Добавлена поддержка виртуального столбца _etag для хранилища HDFS #108255 (zhangyifan27).
  • В system.backups и system.backup_log добавлены столбцы settings и engine_settings. settings содержит запрошенные для операции настройки резервного копирования и восстановления (например, allow_s3_native_copy, deduplicate_files, structure_only), а engine_settings — настройки, фактически используемые модулями чтения и записи движка резервного копирования (например, настройки запросов S3, такие как allow_native_copy, которые после слияния с конфигурацией конечной точки могут отличаться от запрошенных). Так можно узнать, с какими настройками на самом деле выполнялась операция BACKUP/RESTORE. #108334 (jkartseva).
  • Добавлены system.s3_queue_metadata и system.azure_queue_metadata для просмотра состояния зарегистрированных таблиц S3Queue и AzureQueue в Keeper, включая количество обработанных, обрабатываемых и завершившихся ошибкой файлов. #108522 (kssenii).
  • Использование памяти кэшем заголовков текстового индекса сокращено в 2–2,5 раза. Теперь в кэш (настройка text_index_header_cache_size) помещается больше заголовков частей данных, что уменьшает количество чтений с диска при запросах текстового поиска. #109332 (CurtizJ).
  • В представления INFORMATION_SCHEMA добавлены столбцы для совместимости с MySQL: SCHEMATA.DEFAULT_COLLATION_NAME и DEFAULT_ENCRYPTION; TABLES.ENGINE и связанные столбцы MySQL; а также COLUMNS.COLUMN_KEY, PRIVILEGES, GENERATION_EXPRESSION, SRS_ID. Благодаря этому клиенты, работающие с MySQL, могут выполнять запросы интроспекции каталога, не получая ошибку UNKNOWN_IDENTIFIER. #109351 (alexey-milovidov).
  • Сокращено использование памяти таблицами MergeTree с большим числом частей данных: производные от схемы метаданные частей (список столбцов, описания столбцов, сериализации и подпотоки столбцов) теперь используются всеми частями таблицы совместно, а не копируются в каждую часть. Наибольший эффект достигается для широких таблиц с множеством мелких частей. #109816 (Algunenano).
  • Добавлена новая настройка use_projection_index_in_read_pools (по умолчанию отключена). Если она включена, диапазоны меток, полностью отфильтрованные индексом-проекцией, отбрасываются внутри пулов чтения MergeTree ещё до создания для них задач чтения, а не пропускаются гранула за гранулой в процессе чтения. Это позволяет не создавать задачи чтения и не настраивать читатели для данных, которые всё равно не будут прочитаны, а размер задач чтения при этом измеряется в оставшихся метках. #110291 (KochetovNicolai).
  • Уменьшен объём диагностических сообщений двоичного поиска по первичному ключу для каждой части в MergeTree: уровень логирования понижен с trace до test. #110324 (alexey-milovidov).
  • Исправлены ложные переподключения keep-alive HTTP-соединений из пула поверх TLS (HTTPS, S3). Проверка устаревших соединений использовала poll на сокете, из-за чего живое защищённое соединение с непрочитанной TLS-записью, полученной после рукопожатия (тикет сессии или KeyUpdate), ошибочно считалось закрытым. Теперь для обычных сокетов используется неблокирующий MSG_PEEK, а для TLS-сокетов — SSL_peek/SSL_has_pending, что также позволяет корректно обнаруживать штатное завершение TLS-сессии и TLS-запись, пришедшую лишь частично. #110402 (alexey-milovidov).
  • Каталоги OneLake теперь могут использовать токены обновления OAuth для продления токенов доступа. #110413 (alesapin).
  • Добавлено событие ProfileEvent DuplicationDataHashComputations, которое подсчитывает поколоночные вычисления хешей данных, выполняемые при дедупликации вставляемых блоков в таблицы *MergeTree. #111173 (valerypetrov).
  • SST индекса UNIQUE KEY теперь записывается непосредственно в часть через абстракцию хранилища, без промежуточного сохранения в локальный временный файл. #111189 (JingYanchao).
  • Добавлена поддержка конкурентной записи в таблицы Iceberg на локальном диске: LocalObjectStorage теперь реализует условную запись, поэтому операция compare-and-swap, публикующая новый снимок через version-hint.text, работает и здесь, а конкурентные писатели больше не могут потерять обновления друг друга. #112556 (alexey-milovidov).
  • Кеш регионов бакетов клиента S3 теперь работает и для каталогов озёр данных; ранее при каждом запросе к ним регион определялся заново. #113330 (scanhex12).
  • Сетевые сбои на стороне клиента Azure (сброс соединения или отказ в соединении, ошибки DNS и TLS) теперь обрабатываются как транспортные ошибки с повторными попытками, а не возвращаются в виде искусственной ошибки 500, — так же, как в клиенте S3. #115269 (arsenmuk).

Форматы и ингестия

  • Добавлена поддержка сжатия snappy в HTTP-интерфейсе (Accept-Encoding: snappy), а также настройка snappy_mode, позволяющая выбрать блочный формат Hadoop snappy или формат фрейминга snappy для операций ввода-вывода snappy в универсальных функциях file/url. #100752 (alexey-milovidov).
  • Добавлена настройка input_format_csv_missing_nullable_as_empty_string (по умолчанию отключена). Если она включена, отсутствующее значение типа Nullable(String) во входных данных CSV считывается как пустая строка String, а не как NULL, независимо от значения input_format_csv_empty_as_default. #107577 (alexey-milovidov).
  • При обработке сообщений protobuf с настройкой input_format_protobuf_oneof_presence точное совпадение тегов больше не требуется, что позволяет изменять схему. #109174 (ilejn).
  • Удалён устаревший считыватель ORC на основе Apache Arrow. Входной формат ORC теперь всегда использует нативный декодер ClickHouse (ранее он применялся по умолчанию). Настройка input_format_orc_use_fast_decoder устарела (она по-прежнему принимается, но ни на что не влияет). #110074 (alexey-milovidov).
  • Движок Hive теперь считывает метаданные ORC-файлов (индексы min/max, количество строк) с помощью нативного считывателя ORC в ClickHouse вместо адаптера Apache Arrow ORC. #110086 (alexey-milovidov).

Безопасность, доступ и обсервабилити

  • В таблицу system.tables добавлен новый столбец skipping_indices_types. Он содержит уникальные типы индексов пропуска данных, определённых для каждой таблицы. #106388 (CurtizJ).
  • Автоматическое значение max_threads и аналогичных настроек теперь отображается в system.settings как auto(8) вместо 'auto(8)': обрамляющие одинарные кавычки были давним артефактом, намертво встроенным в значение. Совместимость между версиями сохранена: при разборе настроек, полученных от серверов более старых версий, устаревшая форма в кавычках по-прежнему принимается. #108657 (alexey-milovidov).
  • Пустое значение настройки по умолчанию теперь отображается в system.documentation как пустая строка, а не как пустые обратные кавычки. #108708 (alexey-milovidov).
  • Документация настройки в system.documentation, которая выводится встроенной страницей /docs и командой help, теперь включает историю изменений её значения по умолчанию: версию, в которой настройка появилась, и все последующие изменения значения по умолчанию с указанием предыдущего и нового значений, а также причины изменения. #112177 (alexey-milovidov).
  • Документацию по всем SQL-командам (имя, синтаксис, описание, примеры и т. д.) теперь можно получить из системной таблицы system.statements. #115341 (rschu1ze).

Настройки и конфигурация

  • Добавлена новая настройка сервера memory_worker_rss_speculative_reserve_ratio (по умолчанию 1.0, или 0 в сборках с санитайзерами), при которой глобальный трекер памяти на каждом такте MemoryWorker спекулятивно резервирует ratio * min(resident - previous_resident, resident - tracked) сверх наблюдаемого RSS. Это смещает показания трекера вверх, когда рост RSS между замерами опережает учёт трекера, поэтому выделения памяти раньше получают MEMORY_LIMIT_EXCEEDED, а вероятность того, что OOM-killer ядра сработает первым, снижается. Чтобы отключить спекулятивное резервирование, установите долю в 0. В сборках с санитайзерами значение по умолчанию — 0, поскольку разрыв resident - tracked там в основном обусловлен теневой памятью санитайзера. #104976 (alexey-milovidov).
  • Режим отложенного применения списков вхождений (posting lists) текстового индекса больше не является экспериментальным: его можно выбрать с помощью text_index_posting_list_apply_mode = 'lazy' без allow_experimental_text_index_lazy_apply. Настройка порога плотности переименована из text_index_density_threshold в text_index_lazy_intersection_density_threshold. #108814 (CurtizJ).
  • Настройка merge_selector_enable_heuristic_to_lower_max_parts_to_merge_at_once теперь включена по умолчанию: селектор слияний автоматически уменьшает максимальное количество частей, объединяемых за одно слияние, в зависимости от заполненности партиции. #110726 (Michicosun).
  • Команды очистки PostgreSQL RESET, UNLISTEN и DISCARD теперь принимаются в PostgreSQL wire protocol как пустые операции, а не завершаются синтаксической ошибкой. Это улучшает совместимость с драйверами вроде Skunk, которые отправляют RESET ALL и UNLISTEN * при установке и закрытии соединения. #110780 (alexey-milovidov).
  • Текстовые AI-функции (aiGenerate, aiClassify, aiExtract, aiTranslate) теперь отклоняют усечённые или иным образом неполные ответы провайдера (например, когда модель достигает лимита max_tokens), вместо того чтобы молча возвращать частичный результат. Поведение определяется настройкой ai_function_throw_on_error. #111830 (george-larionov).
  • Улучшены функции пониженной точности L2DistanceTransposedQuantized, cosineDistanceTransposedQuantized и dotProductTransposedQuantized за счёт восстановления кодов p < 8QBit(Int8) с помощью префиксных центроидов на основе гауссова условного среднего. При полной точности (p = 8) результаты остаются побитово идентичными; приближённые расстояния при пониженной точности могут измениться, а выигрыш в полноте и задержке зависит от нагрузки. #111867 (skuznetsov).
  • Настройка write_snapshot_version теперь поддерживает горячую перезагрузку. #112150 (alesapin).
  • Добавлены средства обсервабилити стеков файберов, используемых для асинхронного взаимодействия с удалёнными репликами: события профилирования FiberStackAllocs, FiberStackAllocBytes, FiberStackAllocNanoseconds, FiberStackFreeNanoseconds и метрики FiberStacks, FiberStackBytes. #114541 (alexey-milovidov).
  • Протокол Prometheus remote-write теперь поддерживает асинхронные вставки: данные из нескольких одновременных запросов remote-write объединяются в пакеты перед формированием частей в соответствии с настройкой async_insert (включена по умолчанию; чтобы сохранить синхронное поведение, добавьте async_insert=0 в URL обработчика). Запрос подтверждается только после сброса данных во все внутренние таблицы целевой таблицы TimeSeries. #115688 (nikitamikhaylov).

Другие улучшения

  • Добавлены две настройки, shrink_over_allocated_columns_min_waste_ratio и shrink_over_allocated_columns_min_waste_bytes, при включении которых INSERT перед материализацией и записью частей ужимает до фактического размера столбцы с избыточно выделенной памятью (когда зарезервированная память превышает используемую из-за роста столбцов переменной длины по степеням двойки), что снижает пиковое потребление памяти. По умолчанию отключены. #112161 (Avogar).
  • Для слияний TTLDrop этап чтения данных теперь полностью пропускается, чтобы избежать чрезмерного использования памяти, особенно на выделение буферов чтения/предварительной выборки. #105859 (Avogar).
  • Добавлена поддержка BFloat16 в dotProduct; кроме того, скалярное произведение стало вычисляться быстрее благодаря пакетной обработке в SIMD-ветке. #106569 (nickitat).
  • Настройки max_named_collection_num_to_throw, max_table_num_to_throw, max_replicated_table_num_to_throw, max_view_num_to_throw, max_dictionary_num_to_throw и max_database_num_to_throw теперь можно изменять без перезапуска сервера. #106821 (UberDever).
  • Запись в таблицы DeltaLake, управляемая настройкой allow_experimental_delta_lake_writes, переведена в статус Beta. #107034 (kssenii).
  • Добавлен тип статистики столбцов uniq_v2 — легковесная альтернатива uniq на основе скетча uniqCombined64. #107863 (hanfei1991).
  • Добавлены ProfileEvents DistributedPlanRemoteTasks, DistributedPlanLocalExecution и DistributedPlanHostsUsed для отслеживания выполнения make_distributed_plan. #107985 (shankar-iyer).
  • Запросы к REST-каталогам озёр данных, например OneLake, теперь содержат заголовок User-Agent с идентификатором ClickHouse. #108117 (scanhex12).
  • MVTEncodeGeom теперь привязывает геометрию к целочисленной пиксельной сетке перед отсечением и отсекает полигоны с помощью wagyu, поэтому результат отсечения корректен (самопересекающиеся кольца исправляются) и выровнен по границам — так же, как в PostGIS ST_AsMVTGeom. #108248 (saarthak2002).
  • Все три кэша текстового индекса теперь включены глобально — ранее они включались только в рамках запросов. Кроме того, размер кэша списков вхождений теперь равен нулю (что фактически снова его отключает), поскольку списки вхождений велики и их кэширование обходится слишком дорого. #108274 (rschu1ze).
  • Конечная точка Prometheus (для конфигураций, предназначенных только для метрик) и асинхронный сбор метрик теперь запускаются до загрузки таблиц, чтобы метрики были доступны во время потенциально длительной загрузки метаданных. #108402 (cwurm).
  • Добавлена поддержка BFloat16 в бинарных математических функциях #108442 (zhangyifan27).
  • Транспонированные функции векторного расстояния L2DistanceTransposed, cosineDistanceTransposed и dotProductTransposed теперь применяют оптимизацию частичного чтения битовых плоскостей к столбцам Nullable(QBit), считывая только запрошенные битовые плоскости, а не весь столбец. #109358 (alexey-milovidov).
  • Добавлена поддержка arraySum, arrayAvg и arrayProduct для массивов типа BFloat16. #109420 (alexey-milovidov).
  • Функции L1Normalize, L2Normalize, LinfNormalize и LpNormalize (а также их псевдонимы) теперь работают не только с кортежами, но и с массивами — аналогично L2Norm и функциям расстояния. #110052 (alexey-milovidov).
  • Соединения из пула больше не проверяются с помощью ping перед каждым использованием. Это устраняет дополнительный обмен Ping-Pong при каждом повторном использовании соединения и снижает задержку распределённых запросов и clickhouse-benchmark. Устаревшее соединение из пула обнаруживается с помощью poll с нулевым тайм-аутом (неблокирующая проверка, не требующая обмена с сервером) и восстанавливается путём повторного подключения. #110068 (alexey-milovidov).
  • Большие списки кусков для распределённого анализа индексов теперь передаются как скаляры (это предотвращает возможные сбои из-за max_ast_elements/max_query_size и устраняет накладные расходы на разбор AST) #110419 (azat).
  • Нажатие на логотип облака в Песочнице ClickHouse теперь открывает сайт ClickHouse в новой вкладке, чтобы не потерять прогресс выполняющихся запросов. #110422 (williamhatcher).
  • Значение auto_statistics_types по умолчанию изменено с basic, uniq на basic, uniq_v2 #110878 (hanfei1991).
  • При срабатывании проверки повторного входа в RWLockImpl::getLock() (RWLock is already locked in exclusive mode / Cannot acquire exclusive lock while RWLock is already locked) сообщение об ошибке теперь содержит query_id других запросов, удерживающих блокировку, а также количество блокировок, которые уже удерживает запрашивающий query_id. Это упрощает диагностику ошибок, связанных с порядком захвата блокировок. #110971 (groeneai).
  • randomHadamardTransform теперь вычисляет точное преобразование с сохранением длины для любой длины вектора, наибольший нечётный множитель которой не превышает 64 (например, 3584 = 512 * 7 — распространённая размерность в моделях эмбеддингов). Это расширяет ранее поддерживаемые семейства 2^N, 2^k * {12, 20} и 2^k * 9. Полное преобразование для длины, которую невозможно представить точно, теперь вызывает исключение вместо неявного дополнения нулями до более длинного вектора; чтобы вычислить усечённую проекцию произвольной длины, передайте output_dims. #111006 (alexey-milovidov).
  • Для исключений ACCESS_DENIED в HTTP-интерфейсе теперь возвращается HTTP-код 403 Forbidden (вместо 500 Internal Server Error). #111043 (Schum-io).
  • UTMToGeo теперь принимает в качестве четвёртого аргумента букву широтной зоны MGRS, возвращаемую geoToUTM (помимо целочисленного флага полушария), поэтому результат geoToUTM можно напрямую передать в UTMToGeo без потерь. #111521 (alexey-milovidov).
  • MaterializedPostgreSQL теперь сохраняет неизменённые значения PostgreSQL TOAST при обновлениях, а не заменяет их значениями по умолчанию. #111552 (OrpheusAgent).
  • Добавлены настройки text_index_max_processed_tokens_before_flush и text_index_max_memory_usage_before_flush, позволяющие управлять тем, когда построители текстового индекса сбрасывают временные сегменты на диск. #111573 (rorylshanks).
  • Добавлен модификатор STREAM UNORDERED, который отключает сортировку по порядку коммитов в рамках каждого снимка #111794 (SmitaRKulkarni).
  • Теперь make_distributed_plan=1 отключает возможности, которые пока не поддерживаются. #112463 (alesapin).
  • ANSI-последовательности экранирования больше не записываются в файл, указанный в предложении INTO OUTFILE, если stdout является tty #113252 (azat).
  • Настройка allow_experimental_delta_kernel_rs переименована в allow_delta_kernel_rs. Старое имя сохранено как псевдоним. #113476 (kssenii).
  • Добавлены настройки enable_alp_codec, enable_sz3_codec, enable_zxc_codec и enable_quantized_codec, позволяющие включать каждый экспериментальный кодек сжатия по отдельности. #113824 (rienath).
  • Теперь при переполнении стека выводится сообщение об ошибке, а не происходит молчаливое аварийное завершение: обработчики фатальных сигналов выполняются на альтернативном стеке сигналов, поэтому при SIGSEGV, SIGABRT, SIGILL, SIGBUS, SIGSYS, SIGFPE и SIGTRAP выводится трассировка стека, даже если сбойный поток исчерпал свой стек. #113927 (groeneai).
  • Добавлена поддержка параметра lookback_delta из Prometheus HTTP API для мгновенных запросов и запросов по диапазону. #113971 (fallintoplace).
  • Таблицы QueryRunner теперь запускают рабочие потоки по мере необходимости и освобождают их при простое, а не занимают потоки на протяжении всего времени существования таблицы. #114522 (mstetsyuk).
  • Теперь при использовании индексов WHATIF базовый вариант, обслуживаемый проекцией, возвращает not_applicable для каждого кандидата, а не завершает выполнение оператора с ошибкой. #114846 (yariks5s).
  • Оптимизированы цепочки AND с несколькими условиями сравнения для одного и того же выражения: обнаруживаются противоречия (например, a < 3 AND a > 5 → false) и отбрасываются избыточные условия (например, a = 3 AND a < 5 → a = 3). #99736 (wudidapaopao).

Исправления ошибок

Исправления в MergeTree, репликации и хранилище

  • Исправлено состояние гонки между ALTER TABLE ... RENAME COLUMN и параллельным OPTIMIZE TABLE ... FINAL (или любым фоновым слиянием) в MergeTree, из-за которого данные переименованного столбца могли незаметно заменяться значениями по умолчанию. Окно гонки между публикацией новых метаданных в памяти и регистрацией мутации переименования в current_mutations_by_version теперь закрыто: currently_processing_in_background_mutex удерживается на протяжении обеих операций. #104822 (groeneai).
  • Исправлены некорректные результаты запросов при использовании GROUP BY с ORDER BY и arrayJoin в проекции. #101775 (Onyx2406).
  • Недопустимые настройки размера загрузки в Azure (например, azure_min_upload_part_size = 0 или azure_max_blocks_in_multipart_upload = 0) теперь отклоняются на раннем этапе с понятной ошибкой, а не вызывают внутреннее исключение (second_size > 0) глубоко в пути записи. Это относится как к настройкам запроса, так и к конфигурации диска Azure. #103394 (statxc).
  • Теперь генерируется исключение BAD_ARGUMENTS вместо LOGICAL_ERROR, когда ALTER TABLE ... MOVE/REPLACE/ATTACH PARTITION выполняется между двумя таблицами MergeTree с несовместимыми настройками гранулярности (одна адаптивная, другая неадаптивная). #103881 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR «Expected one block from input stream», возникавшая в KILL QUERY / KILL MUTATION / KILL PART_MOVE_TO_SHARD / KILL TRANSACTION, если их предложение WHERE содержит построчный подзапрос или если значение max_block_size настолько мало, что внутренний SELECT по соответствующей таблице system.* возвращает более одного блока. #104927 (groeneai).
  • Исправлена утечка в Refreshable Materialized Views (MATERIALIZED VIEW ... REFRESH ...): временную внутреннюю таблицу, которую задача обновления выводит из ротации через EXCHANGE TABLES, не удавалось удалить, если её размер превышал заданный на сервере max_table_size_to_drop. Каждое последующее обновление создавало ещё одну временную внутреннюю таблицу, так и не удаляя предыдущие, и каталог данных представления разрастался, пока на диске не заканчивалось место. Внутреннее удаление в задаче обновления теперь игнорирует max_table_size_to_drop и max_partition_size_to_drop; эти защитные ограничения по-прежнему действуют, когда пользователь сам выполняет DROP TABLE для представления. #105106 (groeneai).
  • Исправлена неожиданная ошибка DATA_TYPE_CANNOT_BE_USED_IN_KEY в запросах ALTER, которые не могут изменить ключ сортировки (настройки, комментарии, кодеки, добавление неключевого столбца и т. д.), для таблиц MergeTree, у которых в ключе сортировки есть SimpleAggregateFunction (или другой тип, допустимый только при allow_suspicious_primary_key = 1). #105111 (groeneai).
  • OPTIMIZE ... DRY RUN, прерванный по тайм-ауту запроса (max_execution_time с timeout_overflow_mode = 'break'), теперь возвращает TIMEOUT_EXCEEDED вместо логической ошибки, связанной с rows_sources (в отладочных сборках и сборках с санитайзерами она приводила к аварийному завершению сервера). #107114 (groeneai).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK при чтении файлов с hive-партиционированием при use_hive_partitioning=1 и предложении WHERE/PREWHERE, фильтрующем реальный (не виртуальный) столбец, если одновременно выбирается и столбец hive-партиции. #107505 (groeneai).
  • Исправлены неверные результаты запросов, вызванные некорректным отсечением по первичному ключу и партициям, когда toStartOfDay, toStartOfISOYear, toDaysSinceYearZero, toRelativeSecondNum, toRelativeMinuteNum, toRelativeHourNum, toRelativeWeekNum, toRelativeDayNum, toMonthNumSinceEpoch или toYearNumSinceEpoch применяется к ключевому столбцу типа Date32, содержащему даты вне диапазона, представимого функцией (в частности, даты до 1970-01-01). Эти функции сообщают первичному индексу, что они монотонны, однако ранее для таких аргументов их значения переполнялись и «заворачивались», из-за чего индекс мог отсекать гранулы, на самом деле содержавшие подходящие строки. Теперь значения ограничиваются границами типа результата (насыщение), функции остаются монотонными на всём диапазоне Date32, и отсечение работает корректно. #108018 (nihalzp).
  • Исправлена ошибка, из-за которой CREATE TABLE dst AS src SETTINGS ... (и аналогичные варианты с ORDER BY/PARTITION BY, но без явного ENGINE) молча отбрасывали движок исходной таблицы, секции хранения (например, TTL таблицы и ключи) и настройки. Теперь движок и непереопределённые секции хранения наследуются от исходной таблицы, а указанные настройки применяются поверх настроек исходной таблицы. #108085 (alexey-milovidov).
  • Исправлен сбой INSERT в таблицы MergeTree с ошибкой filesystem error: in rename: Permission denied на файловых системах на базе Windows (WSL, CIFS/SMB, bind mounts в Docker Desktop): модуль записи частей оставлял файловые дескрипторы открытыми во время переименования каталога части. #108089 (alexey-milovidov).
  • Исправлено зависание таблицы MergeTree, подключённой с устаревшим пропускающим индексом hypothesis (удалённый тип индекса, сохранённый только для совместимости с ATTACH). Ранее облегчённый DELETE, OPTIMIZE, обычный INSERT или SELECT с фильтром для такой таблицы завершались ошибкой ILLEGAL_INDEX (“Index of type ‘hypothesis’ is no longer supported”), а мутация DELETE повторялась бесконечно. Теперь неработающий индекс считается инертным: при слиянии и мутации он переносится без изменений, игнорируется при вставке и планировании запроса и по-прежнему может быть удалён с помощью ALTER TABLE ... DROP INDEX. #108217 (groeneai).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK (например, Column _part not found) при выборке виртуальных столбцов из таблицы MergeTree с параллельными репликами, в том числе через SELECT * при asterisk_include_virtual_columns = 1. #108451 (groeneai).
  • Исправлена ошибка, из-за которой ATTACH PARTITION ... FROM отклонял таблицы с эквивалентными, но по-разному объявленными первичными ключами (в одной — явный PRIMARY KEY, в другой — неявный из ORDER BY). #108590 (jordiori).
  • Настройка join_any_take_last_row теперь учитывается во всех поддерживаемых вариантах хеш-JOIN, включая JOIN с автоматическим сбросом данных на диск. #108936 (antaljanosbenjamin).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK, возникавшая при включённой настройке query_plan_optimize_lazy_final в сочетании с фильтром WHERE, частично перенесённым в PREWHERE (через optimize_move_to_prewhere_if_final). Отложенная оптимизация FINAL больше не запрашивает из хранилища столбцы предикатов, вычисляемые в prewhere. #109073 (groeneai).
  • Исправлена ошибка, из-за которой ALTER TABLE ... ADD PROJECTION над столбцом ALIAS уровня таблицы делал таблицу непригодной для использования (последующий INSERT завершался ошибкой UNKNOWN_IDENTIFIER, “Missing columns”), если в сессии был задан optimize_respect_aliases = 0. #109091 (groeneai).
  • Исправлено срабатывание проверки на нулевой указатель (px != 0 в TreeRewriter::analyzeSelect, приводившее к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами) при выполнении ORDER BY ALL (или GROUP BY ALL) над таблицей на движке Merge, соединённой с другой таблицей, при использовании старого анализатора (allow_experimental_analyzer = 0). #109139 (groeneai).
  • Исправлен неверный результат коррелированных подзапросов EXISTS и скалярных подзапросов в случае, когда корреляция присутствует только в проекции подзапроса, а предложение WHERE некоррелированное (подзапрос мог возвращать false / NULL для каждой строки). Исправляет https://github.com/ClickHouse/ClickHouse/issues/105760. #109186 (novikd).
  • Исправлена ошибка, из-за которой слияние таблицы MergeTree с проекциями при включённой настройке enable_block_number_column или enable_block_offset_column создавало части проекций с лишним столбцом _block_number/_block_offset. В результате слитая часть проекции переставала соответствовать определению проекции и частям проекций, созданным при вставке, поэтому CHECK TABLE и OPTIMIZE ... DRY RUN сообщали о её повреждении (CORRUPTED_DATA). #109284 (groeneai).
  • Исправлена ошибка UNKNOWN_IDENTIFIER при выполнении ALTER TABLE ... RENAME/ADD/MODIFY COLUMN для таблицы MergeTree с неявным min-max индексом по постоянным виртуальным столбцам _block_number или _block_offset (включается настройками add_minmax_index_for_block_number_column / add_minmax_index_for_block_offset_column). #109428 (groeneai).
  • Исправлена ошибка, из-за которой индексы пропуска удалялись из части данных (или CHECK TABLE завершался ошибкой UNEXPECTED_FILE_IN_DATA_PART) после мутации с полной перезаписью части формата Wide, например ALTER TABLE ... DROP COLUMN для столбца MATERIALIZED. #109616 (groeneai).
  • Исправлена ошибка, из-за которой индексы пропуска (text, bloom_filter и др.) и проекции устаревали после материализации облегчённых обновлений с помощью ALTER TABLE ... APPLY PATCHES. Ранее файлы индексов и проекций, зависящие от столбца, обновлённого патчем, оставались без изменений, поэтому использующие их запросы могли возвращать неверные результаты (например, hasToken пропускал обновлённую строку, а проекция возвращала устаревшие агрегаты после удаления отработанной части патча). #109709 (groeneai).
  • Исправлена ошибка, из-за которой мутация, ссылающаяся на виртуальный столбец _sample_factor, завершалась сбоем посреди выполнения с сообщением Unexpected const virtual column: _sample_factor и зависала. Теперь мутация считывает его как 1 — то же значение, что возвращает запрос без SAMPLE. #109813 (groeneai).
  • Исправлены две ошибки, возникавшие при выполнении запроса с GROUP BY GROUPING SETS (или содержащего такой запрос скалярного подзапроса либо подзапроса мутации) с force_aggregation_in_order = 1: Trying to get name of not a column: ExpressionList при старом анализаторе (enable_analyzer = 0) и Memory bound merging of aggregated results is not supported for grouping sets. для распределённого запроса с enable_memory_bound_merging_of_aggregation_results = 1 при новом анализаторе. #109862 (groeneai).
  • Исправлены три проблемы с use_constant_folding_in_index_analysis: логическая ошибка Invalid partition key size, которая могла прерывать SELECT с обычной проекцией, если в таблице задано part_minmax_index_columns = 'with_block_number_offset'; неверные результаты (строки молча отбрасывались) при фильтрации по ключу партиционирования с делением по модулю, например PARTITION BY id % 200; а также сбой (гонка данных) при запросе к индексу text с токенизатором sparseGrams с предикатом LIKE по множеству партиций при max_threads > 1. #109896 (groeneai).
  • Исправлены неверные результаты при использовании индекса пропуска minmax, построенного по столбцу LowCardinality(Nullable(...)): предикаты WHERE/PREWHERE/HAVING ... IS NULL, передаваемые в хранилище, ранее отсекали все гранулы, и запрос возвращал 0 строк, хотя столбец содержал значения NULL. #110061 (groeneai).
  • Исправлено медленное выполнение запросов ORDER BY ... LIMIT к таблицам Distributed, когда prefer_localhost_replica выбирает локальную реплику. #110136 (EmeraldShift).
  • Исправлено исключение (UNION mode UNION_DEFAULT must be normalized), возникавшее, когда мутация DELETE или ALTER UPDATE использовала операцию над множествами (UNION/UNION ALL/UNION DISTINCT/EXCEPT/INTERSECT) внутри подзапроса в условии WHERE или в присваивании UPDATE. #110196 (alexey-milovidov).
  • Исправлены медленное завершение работы сервера и отсутствие реакции на KILL MUTATION, когда мутация с x IN (subquery) строила множество для подзапроса во время анализа первичного ключа; теперь построение множества отменяется незамедлительно. #110198 (alexey-milovidov).
  • Исправлена гонка между KILL TRANSACTION и ALTER TABLE ... UPDATE/DELETE, выполняемым внутри транзакции: если откат происходил между регистрацией мутации в транзакции и её регистрацией в таблице, оставалась «осиротевшая» запись о мутации. Это вызывало логическую ошибку (Cannot find transaction ... that has started mutation ...) в фоновых задачах и блокировало все последующие мутации затронутых частей до перезапуска сервера. #110226 (tiandiwonder).
  • Исправлена ошибка system.tables для базы данных DataLakeCatalog (Iceberg/Glue): если метаданные одной таблицы не удавалось получить, весь запрос прерывался или таблицы молча пропадали из результата. Теперь такая таблица по-прежнему отображается в списке по имени, а столбцы, для которых требуется открытый объект хранилища (engine, total_rows и т. д.), содержат значения по умолчанию или NULL — независимо от database_datalake_require_metadata_access. При прямом обращении к повреждённой таблице ошибка по-прежнему выводится. #110242 (groeneai).
  • Оценка мощности при выборе порядка JOIN теперь строится на статистике столбцов только по тем частям, которые остались после отсечения по партициям/первичному ключу, а не по всем активным частям. Ранее запрос, затрагивающий лишь небольшую партицию, планировался по статистике всей таблицы (наблюдалась переоценка числа строк в 2500 раз, из-за которой менялась сторона построения hash join), и отключение статистики парадоксальным образом давало более удачный план. Также исправлено: ленивый FINAL молча отключался для отношений MergeTree под JOIN, поскольку мемоизированный результат анализа индексов в оптимизаторе порядка JOIN ошибочно принимался за применённую проекцию. #110283 (skuznetsov-clickhouse).
  • ALTER TABLE ... MOVE/REPLACE PARTITION между двумя таблицами MergeTree с несовместимой гранулярностью (одна адаптивная, другая нет) теперь выбрасывает BAD_ARGUMENTS вместо LOGICAL_ERROR. Пользователь вполне может столкнуться с такой ситуацией, поэтому она не должна приводить к внутренней ошибке (которая в отладочных сборках и сборках с санитайзерами аварийно завершает сервер). #110535 (groeneai).
  • Исправлена ошибка, из-за которой TTL ... DELETE WHERE <cond> никогда не удалял строки, начавшие удовлетворять <cond> после выполнения ALTER TABLE ... UPDATE над столбцом, используемым в WHERE. Теперь мутация пересчитывает TTL строк, поэтому истёкшие строки, ставшие удовлетворять условию, удаляются, а не продолжают незаметно храниться. #110648 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR “Invalid partition key size: 0”, которая могла прерывать INSERT в партиционированную таблицу MergeTree с включённым non_replicated_deduplication_window, если пакет асинхронной вставки дедуплицировался лишь частично (часть значений insert_deduplication_token были дубликатами, а часть — новыми). #110651 (groeneai).
  • Исправлена ошибка, из-за которой свёртка констант в новом анализаторе незаметно меняла тип константного значения Geometry. Geometry — это именованный Variant, альтернативы которого могут иметь одинаковое представление в хранилище (LineString/Ring, MultiLineString/Polygon и пустые значения), поэтому две свёрнутые константы, различающиеся только альтернативой, схлопывались в одну: например, константа MULTIPOLYGON EMPTY превращалась в LINESTRING(). #110709 (groeneai).
  • Исправлен неверный результат (неправильный порядок слияния) для запросов с чтением в порядке сортировки, когда distinct-in-order или aggregation-in-order расширяет чтение до более длинного префикса ключа сортировки, чем тот, для которого ORDER BY подготовил виртуальную строку. Дополнительные столбцы сортировки виртуальной строки заполнялись значениями по умолчанию, что могло нарушать порядок в MergingSortedTransform (и приводить к аварийному завершению с LOGICAL_ERROR в отладочных сборках и сборках с санитайзерами). #110725 (groeneai).
  • Активные роли запроса (SET ROLE / role=) теперь передаются на удалённые узлы при чтении с параллельных реплик и из Distributed-таблиц в кластере с interserver-секретом; ранее вместо них использовались роли пользователя по умолчанию, из-за чего политики строк вычислялись не так, как на узле-initiator. #110867 (evillique).
  • Исправлено редкое состояние гонки, при котором ALTER таблицы ReplicatedMergeTree, изменяющий только комментарий или настройки, мог незаметно отбросить столбец, добавленный параллельным ALTER ... ADD COLUMN, и реплика оставалась с устаревшей структурой таблицы. #111029 (tiandiwonder).
  • Исправлена ошибка NUMBER_OF_COLUMNS_DOESNT_MATCH для GROUP BY с агрегатной функцией над таблицей Merge, оборачивающей таблицу Distributed, когда ключ группировки является функцией от столбца, а агрегатная функция читает тот же столбец (например, SELECT toString(g), min(g) FROM merge_over_distributed GROUP BY toString(g)). #111334 (groeneai).
  • Исправлен неверный результат FULL JOIN с таблицей на движке Join (StorageJoin) и USING, когда левый ключ имеет тип Nullable, а ключ хранилища — нет: для левой строки без соответствия с ключом NULL возвращался 0 вместо NULL. #111371 (groeneai).
  • ALTER TABLE ... DETACH PARTITION/PART теперь выполняет fsync для копии, создаваемой в detached/ (поддерева части, а также цепочки каталогов вплоть до корня диска), если для таблицы включена настройка fsync_part_directory; это касается как формата хранения частей Full (каталог), так и Packed. Ранее fsync для копии никогда не выполнялся, хотя для пустой покрывающей части, удаляющей строки из активного набора, он выполнялся. Поэтому отключение питания сразу после подтверждения могло уничтожить отсоединённые данные на btrfs: несинхронизированные записи каталога копии откатывались, detached/ оставался пустым, и для ATTACH ничего не оставалось. Новое поведение управляется существующей настройкой fsync_part_directory; поведение по умолчанию не изменилось. #111426 (groeneai).
  • Столбец типа Nullable(Nothing) (или любого другого типа, недопустимого в таблицах) теперь отклоняется на этапе CREATE TABLE, если схема выводится из хранилища (например, для таблицы remote()/Remote/Distributed без столбцов поверх представления, выполняющего SELECT NULL). Ранее сохранялись метаданные, которые не удавалось загрузить при следующем перезапуске сервера, из-за чего блокировалась загрузка никак не связанных с ними таблиц. #111487 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Got read request from replica N for unknown stream ...), которая могла приводить к аварийному завершению сервера при чтении с параллельными репликами, если запрос полностью обрабатывался на инициаторе за счёт оптимизации с использованием проекций (точный подсчёт, minmax-подсчёт или сохранённая агрегирующая/обычная проекция, не выбирающая ни одного диапазона). #111689 (groeneai).
  • Исправлен партиционированный INSERT в DeltaLake (allow_experimental_delta_lake_writes=1), который искажал значения партиций, содержащие символы пути, и отклонял NULL. Значение вида a/b без предупреждения записывалось как a, % приводил к созданию файла данных, который затем не удавалось прочитать, а значение партиции NULL вызывало ошибку NOT_IMPLEMENTED. Теперь значения партиций кодируются в один сегмент пути с помощью percent-encoding, исходное значение сохраняется в partitionValues, а не извлекается обратно из пути, а значение партиции NULL (или пустая строка) записывается как __HIVE_DEFAULT_PARTITION__ с записью null в partitionValues. #111793 (groeneai).
  • Исправлены логические ошибки Expected UInt64 column for __grouping_set, got BLOB и ColumnBLOB should be converted to a regular column before usage при выполнении распределённого запроса на шарде с enable_parallel_blocks_marshalling (включено по умолчанию), например при GROUP BY GROUPING SETS на кластере с локальной репликой или при чтении таблицы Merge, охватывающей локальную и distributed таблицу. BlocksMarshallingStep больше не добавляется в планы, блоки которых потребляются в том же процессе. #111997 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Type mismatch when building statistics for column) при мутации MergeTree в таблице, где тип столбца со статистикой был изменён с помощью ALTER MODIFY COLUMN, затрагивающего только метаданные (например, Enum8 на Int8 или DateTime на UInt32). Теперь мутация пересчитывает статистику только для фактически перезаписываемых столбцов, а остальную переносит без изменений. Для столбца, перезаписанного с помощью MATERIALIZE COLUMN, UPDATE столбца, от которого зависит столбец MATERIALIZED, или CLEAR COLUMN, статистика теперь пересчитывается, а не остаётся устаревшей. #112009 (groeneai).
  • Исправлена проблема, из-за которой строки незаметно пропадали из результата, если запрос фильтрует по intDiv(constant, key) или divide(constant, key). Анализ первичного ключа и партиций определял неверное направление монотонности для константы, делённой на столбец ключа, поэтому подходящие гранулы отсекались и запрос без какой-либо ошибки возвращал меньше строк. Также исправлена работа intDiv с беззнаковой константой-делимым, у которой установлен старший бит; монотонность больше не заявляется, если из-за операнда типа Decimal деление вычисляется в собственной разрядности decimal; кроме того, анализ ключа больше не выдаёт ошибку Cannot compare DB::IPv4 with long для корректного запроса, в котором константа IPv4/IPv6 делится на столбец ключа. #112156 (groeneai).
  • Исправлена ошибка, из-за которой параметризованное представление, в теле SELECT которого используется INTERSECT/EXCEPT или цепочка UNION, сочетающая UNION DISTINCT с UNION ALL, классифицировалось как обычное представление. Такое представление успешно создавалось, но его метаданные затем не удавалось прочитать: при загрузке возникала ошибка Invalid storage definition in metadata file, из-за чего представление навсегда становилось незагружаемым, а сервер в отладочной сборке или сборке с санитайзером аварийно завершался при запуске. Кроме того, system.tables.parameterized_view_parameters не показывал для таких представлений никаких параметров. #112211 (groeneai).
  • Исправлена ошибка, из-за которой max_execution_time и KILL QUERY игнорировались, пока запрос вычислял функцию geohashesInBox. Такой запрос разворачивал все строки блока, прежде чем его можно было прервать, поэтому отмена срабатывала лишь через несколько минут; теперь функция проверяет ограничение времени запроса по мере обхода строк. Вычисления внутри сохраняемого табличного выражения, например ключа сортировки, skip-индекса или PARTITION BY, этим исправлением не охвачены и отслеживаются отдельно. #112273 (groeneai).
  • Исправлена логическая ошибка при использовании PREWHERE для Merge-таблицы поверх другой Merge-таблицы или materialized view с отличающимся типом столбца. Также исправлена ситуация, когда политика строк незаметно игнорировалась для таблиц, читающих данные с удалённых серверов (Distributed-таблица или таблица-обёртка над ней), из-за чего могли раскрываться строки, которые политика должна была скрывать; теперь такие запросы отклоняются с ошибкой ILLEGAL_PREWHERE. Вместо этого задавайте такие политики для базовых локальных таблиц на каждом удалённом сервере; обратите внимание, что такая политика по-прежнему не применяется к чтению, передаваемому с serialize_query_plan = 1, — это отдельная, уже существовавшая ранее ошибка. #112326 (PedroTadim).
  • Исправлено чтение устаревшего вторичного (skip) индекса после изменения типа через ALTER TABLE ... MODIFY COLUMN, если соответствующая мутация так и не была выполнена — например, потому что её удалили с помощью KILL MUTATION: гранулы на диске были записаны со старым типом, но декодировались с новым, что приводило к LOGICAL_ERROR, попыткам выделить память объёмом в несколько эксабайт или незаметному возврату неверного результата. Также исправлен неверный результат индекса над выражением, смысл которого меняется, хотя все хранимые байты остаются прежними, поэтому мутация вообще не создаётся: например, при MODIFY COLUMN, изменяющем только часовой пояс DateTime или только пользовательское имя типа, например UInt8 на Bool. Теперь такой индекс для затронутой части пропускается. #112484 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Cannot add transform Resize to Pipes because it has no outputs), возникавшая при выполнении запроса с агрегацией по кластеру с serialize_query_plan = 1 и параллельными репликами на основе плана: шаг слияния изменял размер конвейера до нуля потоков. #112506 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (“Part … contains column … that is absent in table …”), возникавшая, когда реплика ReplicatedMergeTree выполняла мутацию части, полученной с другой реплики, до применения собственного отложенного ALTER ... ADD COLUMN. Теперь такая мутация откладывается до применения изменения метаданных. #112510 (groeneai).
  • Исправлено завышение счётчиков чтения (read_rows, read_bytes, ProfileEvents['SelectedRows'], ProfileEvents['SelectedBytes']) и избыточное списание квот READ_ROWS и READ_BYTES для запросов, у которых ORDER BY сбрасывает данные на диск. Строки, повторно считанные из временных файлов внешней сортировки, ещё раз учитывались как чтения из источника, поэтому запрос со сбросом данных на диск завышал объём прочитанного и мог быть отклонён с ошибкой QUOTA_EXCEEDED, хотя и не выходил за пределы своей квоты. #112645 (groeneai).
  • Исправлено занижение размера результата JOIN со сбросом данных на диск в ProfileEvents['JoinResultRowCount']. Строки, выдаваемые из отложенных бакетов, учитывались только в JoinDelayedJoinedTransformRowCount и не попадали в общий итог. Результаты запросов при этом всегда были корректными — неверным было лишь значение события профилирования. #112673 (groeneai).
  • Исправлена проблема, из-за которой max_execution_time и KILL QUERY незаметно переставали действовать на распределённый запрос, устанавливающий соединения с репликами. Теперь такой запрос останавливается при следующей попытке соединения, а не перебирает все оставшиеся реплики и повторные попытки. #112689 (groeneai).
  • Исправлено применение ALTER к таблицам MergeTree в то время, когда ещё выполняется незавершённая мутация RENAME COLUMN. Это могло несовместимым образом изменить метаданные хранилища и полностью заблокировать последующие мутации. #112783 (Michicosun).
  • Исправлены неверные результаты ORDER BY при чтении из таблицы Merge поверх таблиц Distributed: строки могли возвращаться в неправильном порядке, а при использовании LIMIT часть строк, которые должны были попасть в результат, могла отсутствовать. #112931 (alexey-milovidov).
  • Исправлены неверные результаты при включённой предварительной выборке (prefetch) при чтении из файловой системы, когда столбец Nested читается вместе с подстолбцом, который был удалён и добавлен заново, в таблицах с включённой настройкой share_nested_offsets (по умолчанию). Такой запрос мог возвращать значения по умолчанию для физически присутствующего столбца, который операции ALTER вообще не затрагивали. В объектном хранилище проблема проявляется без каких-либо нестандартных настроек, поскольку remote_filesystem_read_prefetch по умолчанию равно 1; на локальных дисках для этого требуется local_filesystem_read_prefetch = 1. Отдельный дефект, не связанный с предварительной выборкой, по-прежнему портит такие чтения, когда диапазон охватывает несколько блоков; данное исправление его не затрагивает. #112997 (groeneai).
  • Исправлена логическая ошибка Pipeline stuck в запросах, распределяющих данные по партициям, например в оконной функции с PARTITION BY или в JOIN с join_algorithm = 'parallel_full_sorting_merge', когда последующая обработка одного шарда завершалась, пока блок был распределён лишь частично. #113190 (groeneai).
  • Исправлено зависание операторов ALTER, OPTIMIZE, TRUNCATE и операций над партициями с alter_sync = 2 в ReplicatedMergeTree, когда таблица начинает завершать работу, пока оператор ожидает другую реплику, например из-за параллельно выполняемого DROP DATABASE ... SYNC. Теперь такой оператор завершается с ошибкой UNFINISHED, а также учитывает max_execution_time и KILL QUERY. #113228 (groeneai).
  • Исправлена ошибка Cannot insert element into Set (NOT_IMPLEMENTED), возникавшая при включённой настройке read_in_order_use_virtual_row, когда запрос к MergeTree с чтением в порядке сортировки сочетает WITH FILL ... INTERPOLATE с фильтром IN или has. #113264 (groeneai).
  • Исправлена логическая ошибка (исключение) Chunk info was not set for chunk in MergingAggregatedTransform, возникавшая при включённой настройке inject_random_order_for_select_without_order_by, когда агрегирующий запрос читает из таблицы Merge, содержащей дочернюю таблицу Distributed: обёртка со случайной сортировкой ORDER BY rand() больше не добавляется в запросы, план которых строится только до промежуточной стадии. #113266 (alexey-milovidov).
  • Исправлена ситуация, при которой строки никогда не удалялись, если у таблицы MergeTree есть два или более правила TTL ... DELETE WHERE с одинаковым временным выражением, различающиеся только условием WHERE. После слияния с удалением по TTL значение rows_where_ttl_info для части сбрасывалось в ноль, поэтому новые TTL-слияния для неё больше не планировались, а истёкшие строки хранились бессрочно — без какой-либо ошибки или сообщения в логе. #113384 (groeneai).
  • Исправлена ошибка, из-за которой max_execution_time и KILL QUERY игнорировались, пока запрос вычислял функции geohashesInBox, arrayFold, sleep, base58Decode, h3PolygonToCells или h3PolygonToCellsWithContainment внутри выражения, хранящегося в метаданных таблицы, например в ключе сортировки, индексе пропуска данных или ключе PARTITION BY. #113456 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Reading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query plan), возникавшая, когда таблица Merge с несколькими дочерними таблицами читает материализованное CTE, на которое ссылается внешний запрос. #113558 (alexey-milovidov).
  • Исправлена ошибка Logical error: 'Required output position N is out of range for pass-through inputs' в EXPLAIN ANALYZE для таблицы Merge с несколькими дочерними таблицами, PREWHERE по одиночному столбцу и отдельным WHERE. #113725 (groeneai).
  • Исправлена логическая ошибка (Unexpected return type), возникавшая при проталкивании в хранилище фильтра по представлению, тип столбца которого отличается от типа в нижележащем хранилище (например, information_schema.tables, где engine имеет тип Nullable(String), поверх system.tables, где он имеет тип String). #113984 (alexey-milovidov).
  • Исправлена ошибка Not-ready Set is passed as the second argument for function 'in', возникавшая при отмене мутации, предикат которой содержит IN (subquery) (например, с помощью KILL MUTATION или DETACH DATABASE), пока множество для подзапроса ещё строится. #114463 (groeneai).
  • ALTER TABLE ... DROP COLUMN для столбца, используемого в ключе сортировки, первичном ключе или ключе партиционирования, теперь завершается ошибкой ALTER_OF_COLUMN_IS_FORBIDDEN с пояснением — так же, как ALTER TABLE ... CLEAR COLUMN. Ранее возникала малопонятная ошибка UNKNOWN_IDENTIFIER: Missing columns, вызванная пересчётом ключевых выражений. То же относится к удалению или очистке целой группы Nested по её общему префиксу, если какой-либо столбец группы используется в ключе; ранее это могло незаметно уничтожить данные группы или оставить мутацию, которая никогда не завершится. При удалении столбца, используемого только в выражении TTL, теперь также сообщается, какое TTL-выражение будет нарушено #114468 (m7kss1).
  • Исправлена ситуация, при которой столбец, переименованный, удалённый и снова добавленный в одном ALTER, до завершения мутации возвращал значения удалённого столбца вместо собственного значения по умолчанию. #114601 (tiandiwonder).
  • Исправлено чтение подстолбца (.size0, .null, элемента кортежа, String.size) через таблицу Merge, когда в базовой таблице родительский столбец объявлен как ALIAS. Такое чтение возвращало значение типа по умолчанию, а если родительский столбец выбирался в том же запросе, могло вернуть значение постороннего столбца. #114673 (groeneai).
  • Исправлено отсутствие строк в результате SELECT с фильтром pointInPolygon по первичному ключу MergeTree, когда аргумент-полигон является некорректным константным литералом, а validate_polygons = 0. Анализ первичного ключа отсекал гранулы на основе полигона, который так и не был проверен, и отбрасывал гранулы с подходящими строками. #114710 (groeneai).
  • Исправлено форматирование ALTER TABLE ... MATERIALIZE INDEX, MATERIALIZE STATISTICS и MATERIALIZE PROJECTION, при котором терялась секция IF EXISTS, из-за чего отформатированный запрос не совпадал с разобранным. Кроме того, теперь отклоняются четыре JSON-представления AST для ALTER ... STATISTICS, которые SQL-парсер не может сгенерировать и которые при форматировании превращались в другую команду. #115099 (groeneai).
  • Исправлено чтение за границами кэшированных хешей словаря при агрегации или соединении по ключу LowCardinality(String), словарь которого растёт во время агрегации (проявлялось, в частности, через TTL ... GROUP BY). Это могло приводить к неверному хешу, а в сборках с санитайзерами — к ошибке heap-buffer-overflow. #115604 (groeneai).
  • CREATE TABLE и ALTER TABLE теперь запрещают использовать кодеки с потерями, например SZ3, для столбцов, входящих в ключ партиционирования. #115626 (groeneai).
  • Чтение через таблицу Merge, которой соответствует таблица Alias, ссылающаяся на параметризованное представление, больше не вызывает ошибку LOGICAL_ERROR: Table has no columns. (приводящую к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами). Для такой таблицы теперь выдаётся STORAGE_REQUIRES_PARAMETER — та же ошибка, что и для самого параметризованного представления. Для любой другой подходящей таблицы, которая не может предоставить столбцы, вместо внутренней ошибки теперь выдаётся UNSUPPORTED_METHOD. #115896 (groeneai).
  • Исправлен предварительный просмотр «на лету» ожидающей мутации, выражение которой ссылается на _sample_factor. При apply_mutations_on_fly = 1 и наличии секции SAMPLE выражение вычислялось с коэффициентом сэмплирования читающего запроса, а не со значением, которое сохраняет фоновая материализация. В результате строки предварительного просмотра расходились с итоговым материализованным результатом, а ожидающая мутация ALTER TABLE t DELETE WHERE _sample_factor > 1 могла приводить к тому, что чтение с SAMPLE не возвращало ни одной строки. Собственный столбец _sample_factor запроса работает как прежде. #115906 (groeneai).
  • Файлы статистики с версией формата V3 теперь читаются, а не отклоняются с ошибкой ILLEGAL_STATISTICS. Такие файлы создавались только сборками master в течение короткого периода, однако содержащие их части было невозможно прочитать, а на диске только для чтения ALTER TABLE ... MATERIALIZE STATISTICS не может их пересоздать. #116030 (alexey-milovidov).
  • Исправлена ошибка Invalid number of columns in chunk pushed to OutputPort (LOGICAL_ERROR), возникавшая, когда запрос SELECT ... FROM t STREAM ... ORDER BY ... LIMIT n читал таблицу с PROJECTION. Ленивая материализация больше не применяется при чтении STREAM. #116187 (groeneai).
  • ALTER TABLE ATTACH PARTITION FROM больше не реплицируется в реплицируемых базах данных. #94835 (MikhailBurdukov).
  • Исправлено аварийное завершение сервера (в сборках с санитайзерами) и скрытая потеря данных при запуске таблицы, когда откаченная транзакционная часть MergeTree пересекается с закоммиченной частью. Теперь PartLoadingTree::add правильно определяет, какая из двух пересекающихся частей была откачена, исключает её и в правильном порядке переносит её осиротевшие дочерние части под закоммиченную часть. #100992 (tuanpach).
  • Исправлена ошибка, из-за которой indexOfAssumeSorted возвращала неверные результаты для столбцов Array(LowCardinality(String)) в таблицах семейства MergeTree. #101771 (Onyx2406).
  • Исправлены исключения LOGICAL_ERROR при чтении таблиц озёр данных Iceberg или DeltaLake по путям, на которых конвейер чтения может запускаться без закреплённого datalake_table_state, например при параллельных обновлениях метаданных Iceberg или чтении через merge из таблиц DeltaLake. #102033 (groeneai).
  • Исправлена ошибка Logical error: Parsed partition value: ... doesn't match partition value for an existing part with the same partition ID: ..., возникавшая при выполнении OPTIMIZE TABLE ... PARTITION ... (и других запросов, определяющих значение партиции через convertFieldToTypeImpl) для таблиц с ключом партиционирования типа Time. #106202 (groeneai).
  • Исправлена ошибка, из-за которой часть данных ошибочно помечалась как имеющая повреждённую проекцию, если после легковесного удаления не оставалось части проекции — либо когда проекция перестраивалась и не содержала ни одной строки, либо когда она удалялась (lightweight_mutation_projection_mode = 'rebuild'/'drop'). Ранее из-за такого состояния для запросов к этой части отключалась оптимизация с помощью проекций. #106273 (tiandiwonder).
  • Исправлено отставание предупреждений о перегрузке по памяти/CPU/мутациям в system.warnings на один цикл асинхронных метрик (и их отсутствие в первом цикле). #108035 (alexey-milovidov).
  • Исправлено исключение LOGICAL_ERROR (ScatterExchangeStep should have one source shard, got 8) и дублирование строк при запросе к таблице Merge поверх таблиц Distributed или представлений с экспериментальной настройкой make_distributed_plan = 1. #108401 (groeneai).
  • Исправлено аварийное завершение сервера (Sort order of blocks violated) во время слияния, а также некорректное чтение, когда не допускающий NULL элемент LowCardinality столбца Nullable(Tuple(...)) используется как подстолбец (например, в качестве ключа сортировки). #108679 (groeneai).
  • Исправлен сбой в функции Base64Decode встроенной копии Azure SDK, который мог возникать при вызове azureBlobStorage() (и связанных табличных функций/хранилищ Azure), если ключ учётной записи не является корректной строкой Base64. Байт >= 0x80 приводил к чтению за пределами таблицы декодирования, а любой недопустимый байт вызывал неопределённое поведение при сдвиге влево отрицательного значения (аварийное завершение в сборках с санитайзерами). Теперь недопустимые ключи корректно отклоняются. #108716 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (“New empty part is about to materialize but the directory already exist”), которая могла приводить к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами, когда DROP/DETACH/MOVE/REPLACE PARTITION для таблицы семейства MergeTree выполнялась после того, как предыдущая такая операция была прервана (например, из-за отката транзакции или сбоя) и оставила после себя устаревший каталог tmp_empty_<part>. Теперь такой каталог используется повторно, а не приводит к ошибке. #108879 (groeneai).
  • Исправлена ошибка, из-за которой проекция возвращала значение по умолчанию для типа столбца (например, 0) вместо значения DEFAULT из DDL (например, -1) после истечения TTL столбца в широкой части. #109013 (tiandiwonder).
  • Исправлены сбои запросов ALTER для таблиц MergeTree, созданных с пользовательской настройкой disk (SETTINGS disk = disk(...)). #109199 (Michicosun).
  • Исправлено появление устаревших и удалённых строк при чтении таблиц базы данных MaterializedPostgreSQL через таблицу Merge. #109339 (vdimir).
  • Исправлено чтение таблиц Paimon, партиционированных по столбцу BIGINT, значение которого не помещается в Int32. Такие значения партиций усекались (например, 9223372036854775807 превращалось в -1), из-за чего формировался неверный путь партиции и возникала ошибка файловой системы. #109510 (groeneai).
  • Исправлена логическая ошибка («Cannot determine row level filter; 0 columns deleted, 0 columns added») при чтении из таблицы Merge, у дочерней таблицы которой есть политика строк, где фильтром служит просто существующий столбец (например, CREATE ROW POLICY ... USING flag). #109843 (groeneai).
  • Исправлено: IcebergLocal указывал Azure в качестве типа хранилища. #109872 (PedroTadim).
  • CHECK TABLE теперь сообщает о фактическом повреждении части проекции, метаданные которой не удалось загрузить, вместо вводящей в заблуждение ошибки Columns doesn't match ... Expected: 0 columns. #110262 (Algunenano).
  • Исправлен сбой запуска сервера для таблиц MergeTree на дисках объектного хранилища, возникавший, если у оставшегося файла txn_version.txt.tmp повреждены метаданные на уровне диска. #110519 (alexey-milovidov).
  • Исправлена ситуация, при которой таблицу семейства MergeTree с проекцией _part_offset или проекцией порядка коммитов становилось навсегда невозможно подключить, если после отключения allow_part_offset_column_in_projections или allow_commit_order_projection таблицу отсоединяли или перезапускали сервер. Эти две настройки проверяются только при CREATE, поэтому при ATTACH они больше повторно не проверяются. #110570 (groeneai).
  • Исправлена редкая ошибка LOGICAL_ERROR («Unexpected number of parts to remove from parts_queue»), которая могла привести к аварийному завершению сервера с ReplicatedMergeTree, когда две операции с партициями (например, два запроса MOVE PARTITION / REPLACE PARTITION или один такой запрос в гонке с фоновой операцией DROP_RANGE) одновременно отменяли фоновую проверку частей в пересекающихся диапазонах. #110738 (groeneai).
  • Исправлена логическая ошибка Hash is not set for serialization, которая могла возникать, если столбец с кодеком Quantized(...) был вложен в сериализацию, использующую пул, — например, в таблице Merge поверх источников, в которых одноимённый столбец имеет разные типы (объединяемые в Variant). #110776 (groeneai).
  • Исправлена ошибка std::length_error (LOGICAL_ERROR) при чтении таблицы семейства MergeTree с аномально большим значением max_streams_for_merge_tree_reading (близким к максимуму UInt64) в сочетании с allow_asynchronous_read_from_io_pool_for_merge_tree = 1. Теперь значение этой настройки ограничивается тем же пределом, что и max_threads. #110936 (groeneai).
  • Исправлена логическая ошибка Cannot calculate columns sizes when columns or checksums are not initialized, возникавшая при слиянии MergeTree-таблицы с единственным столбцом, для которого задан полностью истекающий TTL столбца (при min_bytes_for_wide_part = 1). #111169 (groeneai).
  • Теперь, если заданы min_rows_to_fsync_after_merge / min_compressed_bytes_to_fsync_after_merge / fsync_part_directory, для файлов текстового индекса слитой или материализованной части выполняется fsync. Ранее только эти файлы части оставались несинхронизированными, поэтому при отключении питания сразу после слияния могла остаться закоммиченная, но повреждённая часть, что приводило к потере данных. #111335 (groeneai).
  • Исправлена работа OPTIMIZE TABLE ... MANIFEST для таблиц Iceberg в случае, когда кортежи партиций в манифесте не соответствуют их спецификации партиционирования #111368 (SmitaRKulkarni).
  • Исправлены чтение за пределами границ (в релизных сборках) / логическая ошибка (в отладочных сборках) в оптимизации ленивой материализации, а также логическая ошибка в Pipe::unitePipes для таблиц Merge, возникавшие, когда оптимизация прямого чтения из текстового индекса оставляла неиспользуемый виртуальный столбец индекса в заголовке чтения MergeTree-таблицы с несколькими индексами text. #111467 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (“Part level Min-Max index was constructed from unexpected columns set”), которая могла прерывать фоновое слияние в отладочных сборках и сборках с санитайзерами после понижения значения part_minmax_index_columns (например, с with_block_number_offset обратно до partition_key_only). #111511 (groeneai).
  • Исправлен сбой при чтении STREAM (enable_streaming_queries = 1) из таблицы, содержащей более одной партиции и имеющей политику строк. В отладочных сборках и сборках с санитайзерами возникала логическая ошибка Filter column ... not found in DAG outputs, а в релизных сборках мог происходить segfault. #111572 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Cannot create part with type Compact and storage type Full because table does not support polymorphic parts), возникавшая, когда MergeTree-таблица загружала ранее созданную часть Compact, хотя её текущие настройки отключают полиморфные части (неадаптивная гранулярность). Это могло происходить, например, когда таблица только для чтения использует общий путь на диске с другой таблицей и перезагружает свои части через SYSTEM RESTART DISK или при запуске сервера. В отладочных сборках и сборках с санитайзерами это исключение приводит к аварийному завершению сервера. #111626 (groeneai).
  • При fsync_part_directory = 1 переименование каталога части из временного имени в окончательное теперь также фиксируется надёжно за счёт fsync родительского каталога (а при перемещении между разными родительскими каталогами — и исходного родительского каталога). Ранее fsync выполнялся только для перемещённого каталога, поэтому при отключении питания сразу после коммита части она могла отсутствовать на диске, хотя её файлы уже были записаны, и строки терялись, несмотря на включённую настройку. #111861 (groeneai).
  • Исправлены неверные результаты и ошибка LOGICAL_ERROR при выборке из MergeTree-таблицы столбца Nullable(Tuple(...)) вместе с одним из его подстолбцов-элементов, способных содержать NULL (Variant, Dynamic или LowCardinality). При чтении подстолбца строки, равные NULL в родительском кортеже, помечались как NULL в столбце, который уже стал общим через кэш подпотоков, из-за чего при чтении всего столбца значения оказывались смещёнными. #111949 (groeneai).
  • Исправлена ошибка, из-за которой hash join терял оптимизации, применяемые после этапа построения (преобразование в хеш-таблицу фиксированного размера, общий runtime-фильтр, переупорядочивание диапазонов правой таблицы), если был настроен порог автоматического сброса на диск, а это поведение по умолчанию начиная с версии 26.5. #111972 (alexey-milovidov).
  • Исправлены неверные результаты (строки незаметно пропадали) для hasAllTokens и других поисков по text-индексу с несколькими токенами в сборках без simdcomp (на всех целевых платформах, кроме x86_64 Linux, например aarch64) при text_index_posting_list_apply_mode = 'lazy'. Переносимый декодер битовой упаковки не записывал декодированные нули для блока с нулевой разрядностью, поэтому элемент списка вхождений, находившийся в сегменте с единственным элементом, отбрасывался. Формат хранения на диске не изменился, и после исправления существующие данные читаются корректно. #112178 (groeneai).
  • Теперь при загрузке повреждённой статистики MergeTree операции завершаются с ошибкой, а не игнорируют её. #112201 (skuznetsov-clickhouse).
  • Исправлена незаметная потеря подтверждённых записей Iceberg в HDFS: коммит Iceberg публикует каждый новый файл метаданных с помощью условной записи, но HDFSObjectStorage отбрасывал условие и выполнял обычную перезапись, поэтому все конкурентные пишущие стороны получали подтверждение, а снимок одной из них становился недостижимым. Теперь HDFS отклоняет условную запись, поэтому управляемые хранилищем записи Iceberg в HDFS, включая CREATE TABLE ... ENGINE = IcebergHDFS(...) с явно заданным списком столбцов, завершаются с ошибкой. Чтение это не затрагивает. #112437 (groeneai).
  • Исправлена ошибка, из-за которой DELETE в таблицах KeeperMap удалял только первые max_block_size подходящих строк, но при этом сообщал об успешном завершении мутации. Также исправлена неатомарность DELETE при keeper_map_strict_mode = 1: он мог переключаться на удаление без учёта версий и удалять строки, параллельно обновлявшиеся другими операциями, а кроме того, применял подходящие строки поблочно, из-за чего при конфликте удаление могло выполниться лишь частично. #112777 (alexey-milovidov).
  • Исправлена ошибка, из-за которой временный сбой Azure Blob Storage при чтении или слиянии — 403 Forbidden из-за задержки распространения разрешений RBAC, сбой аутентификации по учётным данным или тайм-аут подключения, возвращаемый как 408, — ошибочно считался неповторяемым и выдавался как POTENTIALLY_BROKEN_DATA_PART (Code 740), вызывая ложное критическое оповещение для исправной части. Теперь такие временные сбои считаются допускающими повторную попытку, а действительно постоянный сбой выводится как обычная ошибка Azure, а не как несуществующая повреждённая часть данных. #112871 (arsenmuk).
  • Исправлена ошибка, из-за которой listObjects на диске Azure Blob Storage с конечной точкой, содержащей префикс, возвращал неверные имена blob-объектов на всех страницах, кроме первой, поскольку постраничная выборка обходила клиентскую обёртку, удаляющую префикс конечной точки. Теперь постраничная выборка снова проходит через обёртку с использованием токена продолжения, и имена blob-объектов корректны на каждой странице. #112872 (arsenmuk).
  • Исправлена потеря minmax-индекса уровня части по _block_number и _block_offset после перезагрузки таблицы, если часть была создана мутацией, которая не перезаписывает её целиком. #112878 (alexey-milovidov).
  • Исправлено исключение (в релизных сборках — ошибка, препятствующая запуску сервера), возникавшее, когда предикат мутации использует табличную функцию merge без явного указания имени базы данных. Теперь используется база данных изменяемой таблицы — так же, как это делается для имён таблиц. #113185 (alexey-milovidov).
  • Исправлены неверные результаты и ошибка LOGICAL_ERROR при чтении подстолбца удалённого и повторно добавленного члена Nested вместе с существующим членом той же группы в таблице MergeTree с share_nested_offsets = 1. Если чтение охватывало более одного блока, существующие члены возвращали значения из последующего блока. #113225 (groeneai).
  • Исправлено арифметическое исключение в отладочных сборках и сборках с санитайзерами при чтении из таблицы Merge с очень большим значением max_streams_to_max_threads_ratio: количество потоков усекалось до 32 бит, поэтому значения, кратные 2^32, обращались в ноль. Кроме того, если произведение количества потоков для таблицы Merge превышает size_t, теперь выбрасывается PARAMETER_OUT_OF_BOUND вместо неопределённого поведения; устранено переполнение при ограничении количества потоков MergeTree объёмом данных; чтение из таблицы Merge отклоняется, если суммарное количество источников превысило бы 65536. #113382 (alexey-milovidov).
  • Исправлена запись на диск hdfs: она завершалась ошибкой Parent directory doesn't exist, поскольку сгенерированные ключи объектов содержат префикс вложенного каталога, а в HDFS, в отличие от объектных хранилищ, есть настоящие каталоги, и при создании файла отсутствующий родительский каталог не создаётся. #113396 (alexey-milovidov).
  • Исправлено сообщение об ошибке, выдаваемое, когда табличным функциям remote/remoteSecure или движкам таблиц Remote/RemoteSecure передаётся несуществующая именованная коллекция вместе с переопределением key = value. Такой вызов незаметно повторно разбирался как позиционный, поэтому переопределение анализировалось как выражение данных, а в сообщении об ошибке упоминалось нечто постороннее (например, Function with name merge does not exist для remote(collection, database = merge(...))). Теперь сообщается именно об отсутствующей именованной коллекции. #113510 (groeneai).
  • Исправлен бесконечный цикл в фоновых слияниях и OPTIMIZE, когда значение merge_max_block_size_bytes было меньше byteSize() пустого столбца. Пустой столбец LowCardinality всё равно содержит словарь, поэтому лимит по байтам мог быть достигнут до слияния хотя бы одной строки; в результате слияние бесконечно порождало пустые блоки, загружая ядро CPU на 100% и так и не освобождая свой слот в фоновом пуле. #113585 (groeneai).
  • Исправлена ситуация, когда мутация части формата Compact давала разный результат в зависимости от того, находилась ли информация о сериализации части ещё в памяти или была повторно загружена из serialization.json (если таблица использует serialization_info_version = 'basic'). В ReplicatedMergeTree из-за этого две реплики с побайтово идентичной исходной частью записывали разные мутированные части, и мутация завершалась ошибкой CHECKSUM_DOESNT_MATCH. #113588 (groeneai).
  • Если целевое хранилище не может прочитать файл .lock, при резервном копировании теперь сообщается исходная ошибка доступа к файлу блокировки, а не ошибочно — о параллельном резервном копировании. #113637 (kirillshokhin).
  • Исправлена гонка данных между фоновыми задачами таблицы MergeTree (обновление статистики, обновление частей, загрузка устаревших/неожиданных частей) и уничтожением таблицы. #113722 (alexey-milovidov).
  • Исправлено чтение не тех таблиц операциями UPDATE и легковесного DELETE, когда база данных обновляемой таблицы отличается от базы данных сеанса. Выражение мутации теперь канонизируется относительно базы данных обновляемой таблицы — как для табличной функции merge, неявно использующей текущую базу данных, так и для неквалифицированных идентификаторов таблиц. Ранее такие имена разрешались относительно базы данных сеанса, поэтому запрос незаметно обновлял или удалял строки, выбранные из другой таблицы. #113748 (groeneai).
  • Исправлено исключение при чтении таблицы MergeTree по слоям диапазонов первичного ключа, когда слой порождает пустой конвейер. #114177 (alexey-milovidov).
  • BACKUP, RESTORE и ENGINE = Backup теперь проверяют доступ к расположению резервной копии по привилегиям SOURCES пользователя — так же, как это делают s3(), file() и azureBlobStorage(). Ранее пользователь с привилегией BACKUP, но без SOURCES мог записать резервную копию в любое расположение, доступное серверу, и прочитать её оттуда. Теперь для записи резервной копии требуется право WRITE на источник пункта назначения (WRITE ON S3, WRITE ON AZURE, WRITE ON FILE), а для чтения — READ; пункты назначения Disk(...) по-прежнему ограничиваются только настройкой backups.allowed_disk. #114405 (groeneai).
  • Исправлено чтение таблицы во время выполнения мутации: столбец MATERIALIZED мог возвращать устаревшее значение, а его выборка вместе с обновлённым столбцом могла завершаться ошибкой. #114561 (tiandiwonder).
  • Исправлена логическая ошибка (Block structure mismatch) при чтении таблицы Merge с включённым make_distributed_plan, если дочерние таблицы содержат внутренние операции над множествами. #114753 (alexey-milovidov).
  • OPTIMIZE TABLE для таблицы в объектном хранилище, движок которой не реализует компакцию, сообщал об успешном выполнении, фактически ничего не делая. Теперь возвращается ошибка, как и для любого другого движка, не поддерживающего эту команду. Изменение затрагивает DeltaLake, Paimon, Hudi и обычные движки объектного хранилища (S3, GCS, COSN, OSS, AzureBlobStorage, HDFS и URL на базе объектного хранилища); поведение Iceberg, который поддерживает компакцию, не изменилось. #114805 (groeneai).
  • Исправлена ошибка BAD_DATA_PART_NAME («Trying to get part name in new format for old format version») для таблицы ReplicatedMergeTree, созданной с устаревшим позиционным синтаксисом при включённом allow_deprecated_syntax_for_merge_tree. Мутация могла отображаться как завершённая на реплике, которая её не применила, а таблица после перезапуска могла оставаться в режиме только для чтения. #114980 (groeneai).
  • Исправлена ошибка Found patch part ... that intersects mutation with version ... (LOGICAL_ERROR) в таблицах с легковесными обновлениями. Слияние патч-частей могло создать патч, диапазон версий данных которого охватывает версию данных существующей части; такой патч нельзя ни применить, ни пропустить, поэтому все последующие операции над партицией завершались ошибкой, а очередь репликации останавливалась. Такие слияния больше не назначаются. #115064 (alexey-milovidov).
  • Исправлена проблема, из-за которой сервер не запускался, если движок баз данных Backup ссылался на ставшую недоступной резервную копию (например, если её файлы были удалены или нижележащее хранилище недоступно). Теперь база данных загружается без таблиц и не препятствует запуску всего сервера. #83188 (orloffv).
  • Исправлено восстановление логирования после ошибки переполнения диска. Ранее при заполнении диска с логами ClickHouse переходил в состояние сбоя и непрерывно засыпал syslog сообщениями об ошибках (иногда записывая более 100 ГБ в час), не восстанавливаясь даже после освобождения места на диске. Теперь система логирования автоматически восстанавливается, как только на диске появляется свободное место, без перезапуска сервера. #93127 (jaehanbyun).
  • Исправлено аварийное завершение в обходчике схемы в хранилище DeltaLake. #97112 (kssenii).

Исправления для озёр данных и внешних хранилищ

  • Исправлен временный сбой Code: 499 ... InvalidPart (S3_ERROR) при multipart-загрузках в S3 (например, INSERT INTO ... hits_s3). При вызове CompleteMultipartUpload MinIO может на короткое время сообщать об отсутствии только что загруженной части; теперь при этой ошибке выполняются повторные попытки, как и при уже обрабатываемой ошибке NoSuchKey, а их число ограничено параметром s3_max_unexpected_write_error_retries. #109364 (groeneai).
  • Запросы ALTER TABLE ... DELETE и ALTER TABLE ... UPDATE к таблицам Iceberg, формат файлов данных которых отличается от Parquet, теперь отклоняются с понятной ошибкой NOT_IMPLEMENTED, а не приводят к аварийному завершению сервера или незаметному повреждению таблицы. #105893 (groeneai).
  • Исправлена ошибка Cannot add column ...: column with this name already exists при INSERT SELECT из табличной функции, например file, s3 или input, если один и тот же исходный столбец выбирается несколько раз. #105982 (crakjie).
  • Конфиденциальные значения, передаваемые в параметрах строки HTTP-запроса (например, при привязке параметров запроса param_*, таких как param_secret_key/param_aws_secret_access_key, в параметре password или в параметрах signature в стиле S3), больше не записываются как есть в system.text_log и в спаны OpenTelemetry. В строке журнала Request URI значения параметров с потенциально конфиденциальными именами теперь заменяются на [HIDDEN]. #108475 (groeneai).
  • Исправлен виртуальный столбец _etag для движков таблиц S3Queue и AzureQueue: он был объявлен, но не заполнялся, поэтому SELECT _etag всегда возвращал пустую строку. Теперь он возвращает ETag объекта, как и движок S3 и табличная функция s3(). #108625 (groeneai).
  • Запрос на чтение из S3 или запись в S3, отменённый (например, с помощью KILL QUERY) во время выполнения обращения к S3, теперь помечается как отменённый, а не завершается вводящей в заблуждение сетевой ошибкой или ошибкой S3. В частности, для отменённого резервного копирования в S3 или восстановления из S3 в system.backups теперь отображается статус BACKUP_CANCELLED/RESTORE_CANCELLED. #108673 (jkartseva).
  • Исправлен виртуальный столбец _tags для движка таблиц S3Queue: он был объявлен, но не заполнялся, поэтому SELECT _tags всегда возвращал пустой словарь. Теперь он возвращает теги объекта, как и движок S3 и табличная функция s3(). #108676 (groeneai).
  • Исправлена ситуация, когда SHOW TABLES и SELECT … FROM system.tables возвращали разные результаты для баз данных каталогов озёр данных: таблицы, которые ClickHouse не может прочитать, теперь скрываются в обоих случаях. #109273 (SmitaRKulkarni).
  • Исправлено аварийное завершение сервера (а в релизных сборках — незаметно оставшийся нефинализированным файл данных), возникавшее, если INSERT в таблицу Delta Lake (DeltaLakeLocal / deltaLake) завершался ошибкой после того, как приёмник уже начал запись, например когда исходный запрос выбрасывал исключение посреди вставки или запрос отменялся. #109328 (groeneai).
  • Исправлена ошибка Not found column or subcolumn c.null in block (и Bad cast from ColumnConst to ColumnNullable в отладочных сборках и сборках с санитайзерами) при выполнении WHERE col IS NULL / IS NOT NULL для столбца Iceberg, добавленного в ходе эволюции схемы уже после записи более старых файлов данных, при optimize_functions_to_subcolumns=1 (значение по умолчанию). #109515 (groeneai).
  • Исправлена ошибка Host is empty in S3 URI, возникавшая при использовании скалярного подзапроса в качестве аргумента URL табличной функции s3 (или аргумента любой другой табличной функции) в запросах CREATE TABLE ... AS SELECT: теперь скалярные подзапросы в аргументах табличных функций вычисляются на этапе анализа запроса. #110254 (CheSema).
  • Исправлена логическая ошибка (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами) при выполнении для таблицы Iceberg ALTER с несколькими командами, например UPDATE ..., DELETE .... Теперь такие мутации отклоняются с понятной ошибкой NOT_IMPLEMENTED. #110347 (groeneai).
  • Исправлено появление дублирующихся ID полей в таблицах Iceberg после ALTER TABLE ... ADD COLUMN, если исходная схема содержит вложенные поля (Tuple/Array/Map). Теперь last-column-id хранит максимальный назначенный ID поля с учётом вложенных дочерних полей, поэтому добавленный впоследствии столбец больше не получает повторно ID вложенного поля, а чтение больше не завершается ошибкой ICEBERG_SPECIFICATION_VIOLATION (Duplicate field id). #110884 (groeneai).
  • Исправлена ситуация, когда DELETE/UPDATE для таблицы Iceberg молча удаляли не те строки (или выбрасывали NOT_FOUND_COLUMN_IN_BLOCK), если таблица содержит файлы данных, записанные как до, так и после ALTER TABLE ... ADD COLUMN, и включён параметр optimize_move_to_prewhere. #111693 (groeneai).
  • Исправлена ошибка, из-за которой значение made_current_at в system.iceberg_history становилось равным 1970-01-01 для сохранённого снимка после выполнения ALTER TABLE ... EXECUTE expire_snapshots для таблицы Iceberg. Также исправлена ситуация, когда system.iceberg_history не возвращала строк для таблицы, в метаданных которой отсутствует snapshot-log. #111781 (groeneai).
  • Исправлено повреждение данных при вставке в таблицу Iceberg через MATERIALIZED VIEW. Файл данных записывался с типами столбцов целевой таблицы, заданными при CREATE, а не с её актуальной схемой Iceberg, поэтому значение DateTime сохранялось как простой Avro int и при чтении интерпретировалось как микросекунды, а при DateTime64(0) или DateTime64(9) файл и вовсе невозможно было прочитать. Как следствие, INSERT INTO <materialized view> для целевой таблицы, схема Iceberg которой шире объявленных столбцов представления, теперь завершается ошибкой TYPE_MISMATCH вместо записи повреждённой строки. #112359 (groeneai).
  • Исправлена запись в таблицы Iceberg, схема которых содержит кортеж, вложенный в другой кортеж. В публикуемых метаданных таблицы имена полей внутреннего кортежа заменялись позиционными именами 1, 2, …, поэтому при формате по умолчанию Parquet операция INSERT завершалась ошибкой INCORRECT_DATA, а при Avro столбец невозможно было прочитать. #112480 (groeneai).
  • Исправлена взаимоблокировка, которая намертво блокировала базу данных Filesystem или HDFS, когда два запроса одновременно разрешали одно и то же имя таблицы. Все последующие запросы к этой базе данных зависали навсегда без возможности прерывания, и для восстановления приходилось перезапускать сервер. #112495 (groeneai).
  • Исправлена ситуация, когда таблицы DeltaLake возвращали слишком мало строк, если предикат в предложении WHERE содержал под NOT подвыражение, которое транслятор предикатов delta-kernel не может обработать. Теперь такое подвыражение передаётся в delta-kernel как явно неизвестный предикат, а не как конец дочернего итератора, из-за чего раньше охватывающая конъюнкция молча усекалась. #112652 (groeneai).
  • Исправлена ошибка, из-за которой ALTER TABLE ... EXECUTE remove_orphan_files удалял действующий файл metadata/version-hint.text таблицы Iceberg. Запись для этого файла в множестве достижимых файлов формировалась конкатенацией строк в расчёте на завершающую косую черту, которой в значении никогда не бывает. Поэтому реальный файл подсказки не считался достижимым и удалялся, как только становился старше порога older_than. При iceberg_use_version_hint = 1 таблица после этого полностью переставала читаться. #113548 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR при фильтрации по столбцу Iceberg, который стал Nullable после ALTER TABLE ... MODIFY COLUMN. #114521 (groeneai).
  • Исправлена ситуация, когда ATTACH TABLE с определением ENGINE = URL(...) не проверял привилегию TABLE ENGINE для движка, на который перенаправляет схема URL. Пользователь, имеющий только TABLE ENGINE ON URL, мог подключить, а затем читать таблицу на основе File, S3, AzureBlobStorage или HDFS, хотя CREATE TABLE в таком случае корректно отклоняется. #115914 (groeneai).
  • Исправлены сбои исходящих HTTP-запросов (например, `aiGenerate`, табличная функция `url`, S3) с ошибкой `No route to host` на хостах, публикующих адреса как IPv4, так и IPv6, когда маршрутизируемо только одно семейство адресов. Теперь при сетевой ошибке на первом адресе пул HTTP-соединений переключается на следующий разрешённый адрес, а не возвращает ошибку сразу при первом же запросе. #103786 (alexey-milovidov).
  • Добавлена возможность читать Avro array из записей с двумя полями {key, value} в столбец ClickHouse типа Map. Именно такое кодирование Iceberg и Spark используют для MAP<K, V> с нестроковым ключом (нативные map в Avro поддерживают только строковые ключи). Ранее такой файл можно было прочитать как Array(Tuple(key, value)), но не как Map(K, V) — в этом случае возникала ошибка Type Map(...) is not compatible with Avro array. #109289 (groeneai).
  • Исправлено чтение таблицы Iceberg с файлом метаданных, номер версии которого состоит только из цифр, но выходит за пределы диапазона 32-битного целого (например, v99999999999999999999.metadata.json). Ранее такое имя приводило к малоинформативному исключению std::out_of_range (STD_EXCEPTION) вместо понятной ошибки BAD_ARGUMENTS. #109619 (groeneai).
  • Исправлено имя файлов метаданных Iceberg, сжатых gzip. ClickHouse записывал их как v{N}.gzip.metadata.json (по токену HTTP Content-Encoding), тогда как спецификация Iceberg предполагает расширение gz: v{N}.gz.metadata.json. Из-за этого Spark и другие считыватели каталога Hadoop не находили метаданные, записанные ClickHouse. Теперь ClickHouse записывает v{N}.gz.metadata.json, а для обратной совместимости по-прежнему читает устаревшее имя с gzip. #109812 (groeneai).
  • Исправлена ошибка, из-за которой таблица Iceberg с форматом записи Avro сериализовала поле, объявленное как "required": false и имеющее тип list, map или struct, как обязательное, без union ["null", T]. В результате собственная схема файла данных расходилась с метаданными таблицы, и другие считыватели Iceberg видели поле как обязательное. Теперь такое поле записывается как union ["null", T], который спецификация Iceberg использует для необязательных полей. #112648 (groeneai).
  • Исправлена ошибка, из-за которой made_current_at в system.iceberg_history показывал самое раннее время, когда снимок становился текущим, а не самое позднее, если один и тот же snapshot-id встречается в Iceberg snapshot-log более одного раза (как бывает после отката). #113598 (groeneai).
  • Исправлено зависание продолжительностью до одного часа в BACKUP/RESTORE ... TO S3, на дисках GCS и в табличной функции s3, если именованная коллекция задаёт http_client = 'gcp_oauth', а конечная точка выдачи токенов Google OAuth2 принимает соединение, но так и не отвечает. Запрос Bearer-токена больше не наследует таймаут запроса передачи данных вызывающей стороны: время ожидания ответа теперь ограничено 10 секундами — так же, как для запроса STS AssumeRole. #115531 (groeneai).
  • Исправлена логическая ошибка в файловом кэше (Expected file ... not to exist), которая могла возникать, если фоновая загрузка в кэш завершалась сбоем с исключением, отличным от ErrnoException (например, при выполнении OPTIMIZE для таблицы Iceberg), и после неё оставался пустой осиротевший файл кэша. #110549 (groeneai).
  • Исправлена ошибка, из-за которой кэши с ограничением по максимальному числу записей (политика SLRU) незаметно переставали принимать новые записи, как только такое же число записей было запрошено хотя бы дважды. Затронуты кэши файлов метаданных Iceberg и Paimon, кэш метаданных Parquet, кэши текстовых индексов, кэш индексов векторного сходства, кэш скомпилированных выражений и кэш статусов файлов ObjectStorageQueue. #115517 (groeneai).
  • Исправлено чтение таблиц Paimon, которое могло завершаться сбоем при одновременной замене изменяемой подсказки snapshot/LATEST. Если подсказка недействительна или устарела, теперь выполняется безопасный переход к получению списка снимков. #112010 (JiaQiTang98).
  • Теперь выводится реальное исходное исключение, если zip-архив не удаётся распаковать из-за того, что входной буфер (например, буфер чтения S3 с restricted_seek = true) отклоняет запрошенную minizip операцию seek или чтения. Ранее фактическая ошибка скрывалась за общим сообщением Couldn't unpack zip archive: Code = -100 / Couldn't open zip archive. #105103 (groeneai).
  • Исправлена запись в Iceberg для метаданных без refs #106896 (AVMusorin).
  • Исправлено исключение при вставке в таблицу Iceberg, метаданные которой созданы внешним движком и не содержат необязательных массивов snapshots, metadata-log или snapshot-log. Теперь такие вставки выполняются успешно. #107473 (tiandiwonder).
  • Исправлена ошибка ReadBuffer is canceled. Can't read from it., которая могла возникать при повторной попытке загрузки в S3 (например, резервной копии) после временной ошибки чтения. #108573 (groeneai).
  • Исправлена ошибка std::future_error («The associated promise has been destructed prior to the associated state becoming ready»), которая могла возникать (а в отладочных сборках и сборках с санитайзерами — приводить к аварийному завершению сервера), если не удавалось запланировать финальную асинхронную задачу завершения multipart-загрузки в S3/Azure (например, при исчерпании пула потоков). Теперь вместо неё выводится реальная ошибка планирования. #108730 (groeneai).
  • Исправлено чтение временных меток ORC, выходящих за пределы ~2262 года, в столбец DateTime64 с масштабом меньше 9. Нативный считыватель ORC ранее преобразовывал каждую временную метку через промежуточный тип DateTime64(9), который при наносекундном масштабе вызывает переполнение Int64, и отклонял такие значения с ошибкой VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE, даже если запрошенный масштаб DateTime64 (например, DateTime64(6), который создаёт Iceberg) позволяет представить это значение. Теперь временные метки читаются сразу в запрошенном масштабе, а настройка date_time_overflow_behavior учитывается, если значение не помещается даже в целевой масштаб. #109302 (groeneai).
  • При чтении таблицы Paimon, схема которой содержит неподдерживаемый вложенный тип (например, поле ROW), теперь выдаётся понятная ошибка BAD_ARGUMENTS с указанием неподдерживаемого типа вместо пустого DB::Exception. (OK) с кодом ошибки 0 и без сообщения. #109762 (groeneai).
  • Исправлено чтение таблиц Iceberg, партиционированных по одному и тому же исходному столбцу более одного раза (например, PARTITIONED BY (hours(ts), ts)). Ранее при чтении таких таблиц возникала ошибка Cannot add column ...: column with this name already exists (ILLEGAL_COLUMN). #109895 (groeneai).
  • Файлы данных, записываемые ClickHouse в таблицы Iceberg, теперь содержат идентификаторы полей Iceberg для форматов Avro (field-id) и ORC (атрибуты типа iceberg.id/iceberg.required), а столбцы String в ORC записываются как ORC string, а не как двоичные данные. Ранее идентификаторы полей встраивались только в Parquet, поэтому считыватели, соответствующие спецификации (например, Spark/iceberg-java), после переименования столбца молча возвращали NULL для строк Avro, записанных ClickHouse, а ORC-файлы, записанные ClickHouse, не могли прочитать вовсе. #109994 (groeneai).
  • Исправлена логическая ошибка ChunkInfoRowNumbers does not exist при выполнении OPTIMIZE TABLE для таблицы Iceberg, содержащей файл данных в формате, отличном от Parquet (например, ORC), который новее всех файлов позиционного удаления. #110107 (alexey-milovidov).
  • Исправлено чтение больших файлов Parquet из несжатых записей zip-архива типа STORED через s3 и file. #110495 (Gudauu).
  • Сбой запуска фонового пула планировщика (например, пула iceberg при исчерпании глобального пула потоков) больше не приводит к аварийному завершению сервера: теперь такая ошибка является восстанавливаемым исключением. Кроме того, чтение system.background_schedule_pool больше не создаёт эти пулы как побочный эффект. #111209 (groeneai).
  • Исправлена аутентификация DLF в REST-каталоге Paimon: подпись запроса вычислялась один раз и затем использовалась повторно, поэтому все запросы к каталогу, кроме первого, завершались ошибкой HTTP 401, а SHOW TABLES возвращал пустой список. Также исправлено распознавание HTTP 404 при проверке существования таблицы. #112015 (JiaQiTang98).
  • Исправлена ошибка LOGICAL_ERROR (partitions_count > 0) при партиционировании фрагментов данных Iceberg, ставших пустыми после позиционных удалений, например при компактизации партиционированной таблицы Iceberg с полностью удалёнными файлами данных. #112432 (PedroTadim).
  • Исправлена ошибка, из-за которой при пакетном удалении объектов в Azure события Delete не записывались в system.blob_storage_log, если сбоем завершался сам пакетный запрос, и в результате весь батч не попадал в лог. Теперь при сбое на уровне батча событие Delete записывается для каждого объекта. #112873 (arsenmuk).
  • Исправлено чтение таблиц Paimon, партиционированных по столбцу TIMESTAMP с точностью выше миллисекунд, которое завершалось ошибкой scale 6 is not supported, only support scale <= 3. #113401 (JiaQiTang98).
  • Исправлено аварийное завершение при чтении таблицы озера данных, в схеме которой объявлен столбец с пустым именем. Некорректные метаданные Iceberg отклоняются с ошибкой ICEBERG_SPECIFICATION_VIOLATION, а схема, полученная из каталога, Delta Lake или Paimon, — с ошибкой AMBIGUOUS_COLUMN_NAME. Проверка выполняется безусловно, поэтому таблица Iceberg, в которой всего лишь сохранилась неиспользуемая историческая схема с пустым именем поля, тоже становится недоступной для чтения — вместо аварийного завершения в момент чтения этой схемы. #114394 (groeneai).
  • Чтение таблицы Iceberg, метаданные которой описывают изменение схемы, запрещённое спецификацией Iceberg, больше не приводит к аварийному завершению сервера. Четыре нарушения спецификации в IcebergSchemaProcessor либо сообщались как LOGICAL_ERROR, что трактуется как сработавший assert, либо без какой-либо проверки доходили до фатального assert; теперь в этих случаях выбрасывается ошибка ICEBERG_SPECIFICATION_VIOLATION. #114518 (groeneai).
  • Исправлена ошибка, из-за которой виртуальный столбец _time табличных функций url/urlCluster в сборках на основе musl всегда имел значение NULL; причиной был непереносимый разбор HTTP-заголовка Last-Modified. #111619 (thevar1able).
  • Исправлена ошибка, из-за которой сервер не запускался после создания таблицы с помощью CREATE TABLE ... AS url('http://host/**/', ...) при включённой настройке allow_experimental_url_wildcard_from_index_pages. При загрузке метаданных такой таблицы проверка экспериментальной функциональности выполнялась повторно и завершалась ошибкой SUPPORT_IS_DISABLED, что прерывало запуск. #115095 (groeneai).
  • Таблица движка баз данных URL больше не раскрывает пользователю без grant на чтение источника, существует ли локальный файл: ни EXISTS TABLE, для которого требуется лишь привилегия SHOW TABLES, ни разрешение имени таблицы больше не обращаются к файловой системе до подтверждения grant. #113029 (alexey-milovidov).
  • query_masking_rules теперь применяются к сообщениям, добавляемым через Exception::addMessage, поэтому при настроенных правилах маскирования URL-кодированные учётные данные в суффиксах (in file/uri ...) из ошибок jdbc()/odbc() больше не утекают. #106916 (gaurav0107).

Исправления в форматах и ингестии

  • При чтении данных Arrow time32/time64 без схемы (например, SELECT * FROM file(..., 'Arrow')) теперь выводится тип Time64 вместо DateTime64. Ранее выводился DateTime64. Всё, что на последующих этапах обработки рассчитывает на прежний выведенный тип, перестанет работать после обновления. Также добавлена поддержка экспорта Time/Time64 в Arrow: соответствующий тип времени Apache Arrow выбирается в зависимости от точности. #104316 (Maoyao233).
  • Исправлены возможные неверные результаты и чтение за пределами границ при откате INSERT после ошибки в середине пакета (например, в таблицах Buffer, при асинхронных вставках или в движках Kafka/RabbitMQ/FileLog), когда включена отложенная репликация столбцов (enable_lazy_columns_replication). #108935 (groeneai).
  • Исправлена несогласованность парсера: список столбцов в INSERT принимал квалифицированный сопоставитель столбцов вида t.* LIKE '<pattern>' / t.* ILIKE '<pattern>', но отклонял его каноническую форму t.COLUMNS('<regexp>'). Из-за этого нарушалась обратимость форматирования запроса, а в отладочных сборках и сборках с санитайзерами сервер аварийно завершался. #109176 (groeneai).
  • Исправлена ошибка IncorrectEndpointError (HTTP 400) при INSERT в таблицу DataLakeCatalog Microsoft Fabric / OneLake: операции записи ADLS Gen2 (DFS) теперь направляются на хост конечной точки .dfs вместо хоста .blob. Примечание: при использовании remote_url_allow_hosts для работы INSERT в список разрешённых необходимо добавить оба хоста Fabric — .blob (чтение) и .dfs (запись). #110290 (zlareb1).
  • Исправлена запись через табличные функции озёр данных (например, INSERT INTO FUNCTION icebergS3(...)): в создаваемых файлах Parquet строковые столбцы теряли аннотацию типа String, из-за чего внешние системы, такие как Spark, не могли прочитать записанные данные. Теперь такая запись использует те же настройки формата, что и запись через движок таблицы. #110465 (tiandiwonder).
  • Исправлена ошибка, из-за которой таблица system.session_log становилась нечитаемой после входа через Arrow Flight: столбец interface имеет тип Enum8, но в его перечислении отсутствовало значение ArrowFlight. Поэтому при входе по протоколу Arrow Flight записывалось необработанное значение 10, а любой SELECT, читающий такую строку, завершался исключением Unexpected value 10 in enum. #110758 (alexey-milovidov).
  • Исправлен вывод схемы для семейства форматов TSV: для десятичного значения с ведущим нулём, например 0.0 или 0.5, выводился тип String, тогда как CSV корректно выводит Float64. Кроме того, первая строка с такими значениями ошибочно распознавалась механизмом автоопределения заголовка TSV как заголовок и пропадала из результата. Также исправлена ошибка, при которой TSKV выводил числовой тип для значения, записанного с escape-последовательностью, например x=1\x2E5, после чего это значение не удавалось разобрать. Для значений, в которых ведущий ноль служит дополнением целого числа, например 007, по-прежнему выводится String, поскольку парсер значений TSV не может прочитать их обратно. #112226 (groeneai).
  • Исправлена ошибка, из-за которой автоматический вывод схемы предлагал числовой тип для текстовых значений, которые парсер значений не может прочитать обратно. При выводе допускались висячая экспонента (1e+), отсутствующая мантисса (.) или повторяющийся знак (++inf), которые затем отклонялись функцией readFloatTextPrecise с ошибкой CANNOT_PARSE_NUMBER при чтении данных по выведенной схеме; для столбца Dynamic это приводило к ошибке во время INSERT. Теперь при выводе число проверяется тем же парсером, который фактически используется при чтении. Это также устраняет случай, когда выведенный тип зависел от max_read_buffer_size, и позволяет корректным формам экспоненты с ведущим нулём, таким как 0e5, выводиться как Float64 в TSV — так же, как это уже происходит в CSV. Кроме того, исправлена обработка некорректных форм экспоненты. #112453 (groeneai).
  • Исправлена ошибка, из-за которой KILL QUERY и max_execution_time игнорировались в течение нескольких минут, пока построчный входной формат разбирал один блок. Теперь построчные входные форматы проверяют отмену запроса каждые 8192 строки, поэтому завершённая вставка (в частности, фоновый сброс асинхронной вставки, который разбирает до max_insert_block_size строк на блок) останавливается сразу, а не выполняется до конца блока. #112646 (groeneai).
  • Исправлена зависимость выведенного типа столбца от порядка предыдущих запросов для источника, схема которого закэширована. Настройки, влияющие на выведенный тип, не учитывались в ключе кэша вывода схемы, поэтому тип для всех последующих запросов определялся значением из первого запроса: input_format_try_infer_exponent_floats, max_parser_depth, input_format_json_infer_array_of_dynamic_from_array_of_different_types, а для Parquet также input_format_parquet_local_time_as_utc, input_format_parquet_allow_geoparquet_parser, input_format_parquet_skip_columns_with_unsupported_types_in_schema_inference и schema_inference_make_json_columns_nullable. Также зарегистрирован недостающий геттер ключа кэша для Form, а геттер для Template теперь использует правило экранирования собственного формата строк. #113533 (groeneai).
  • Исправлено форматирование аргумента-подзапроса табличных функций view и viewIfPermitted, когда внешний запрос содержит завершающее предложение SETTINGS. Такой запрос форматировался как view((SELECT ...)), что невозможно разобрать обратно, поэтому запрос не проходил внутреннюю проверку «форматирование — разбор — форматирование» и завершался ошибкой Inconsistent AST formatting. #114658 (groeneai).
  • Исправлено ошибочное распознавание данных JSON как TSKV при автоматическом определении формата. #106009 (Avogar).
  • Экспорт значений Time/Time64 за пределами допустимого времени суток (отрицательных или >= 24h) в формат Arrow теперь отклоняется с понятной ошибкой, а не приводит к записи некорректных данных Arrow time32/time64. #107179 (tiandiwonder).
  • Исправлено чтение файлов Arrow, ArrowStream и ORC на основе Arrow, у которых столбец временной метки содержит в качестве часового пояса фиксированное числовое смещение от UTC (например, +05:30, -08:00, 00:00) или не относящийся к IANA маркер fixed; ранее такое чтение завершалось ошибкой Cannot load time zone ... (BAD_ARGUMENTS). #108633 (groeneai).
  • Столбец Nullable(Tuple(...)) теперь сериализуется как одно поле CSV, а не разворачивается в отдельные столбцы. Ранее значение, отличное от NULL, записывалось как несколько полей CSV, а NULL — как одно \N, из-за чего число столбцов зависело от строки, что ломало заголовки CSVWithNames/CSVWithNamesAndTypes и повторное чтение записанных данных. #108959 (groeneai).
  • Исправлено чрезмерное выделение памяти при автоматическом определении схемы для формата MsgPack: если в повреждённых или сгенерированных фаззером входных данных заголовок массива/map/строки/бинарных данных указывает огромное число элементов, это больше не приводит к единовременному выделению нескольких гигабайт памяти (теперь такие данные отклоняются как некорректные). Это устраняет аварийное завершение allocation-size-too-big при работе с санитайзерами и нехватку памяти в релизных сборках. #109019 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR при записи столбца LowCardinality(Time) в формат Arrow с output_format_arrow_low_cardinality_as_dictionary = 1. #109730 (groeneai).
  • Исправлено чтение повреждённого потока в формате Native, в котором количество типов Dynamic или количество путей JSON/Object близко к SIZE_MAX: такие некорректные входные данные теперь отклоняются с понятной ошибкой INCORRECT_DATA вместо неперехваченного исключения std::length_error. #110590 (alexey-milovidov).
  • Исправлена ошибка LOGICAL_ERROR: Cannot sum Bools (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами) при слиянии состояний агрегатных функций sumMap/sumMapWithOverflow/sumMapFiltered со значениями Bool, сериализованными в старом формате состояния (версия 0). Это же исправление устраняет два случая, когда для состояний Bool версии 0 без каких-либо ошибок возвращался неверный результат: ключи map типа Bool не дедуплицировались между состояниями, а при удалении нулевых значений отбрасывались не те записи. #110922 (groeneai).
  • Исправлена ошибка, из-за которой табличная функция format генерировала исключение NOT_FOUND_COLUMN_IN_BLOCK, если при разборе входных данных получалось ноль строк (например, пустой JSON или GeoJSON FeatureCollection без объектов). Теперь возвращается пустой результат с корректными столбцами. #111428 (groeneai).
  • Теперь можно читать файлы GeoParquet, Arrow и ArrowStream, в которых столбец геометрии в кодировке WKT содержит ключевое слово типа не в верхнем регистре (point(1 2)) или пустой контейнер (LINESTRING EMPTY, POLYGON(), POLYGON(())). Ранее импорт таких файлов завершался ошибкой BAD_ARGUMENTS или CANNOT_PARSE_NUMBER, хотя те же строки успешно разбираются функцией readWKT. Также исправлено обратное чтение файла, в котором хранится результат wkt для пустой геометрии, записываемый как LINESTRING(). #112020 (groeneai).
  • Исправлена ошибка Unknown compression method, возникавшая для подсказок сжатия auto и none, записанных в любом регистре, кроме полностью нижнего, например file('data.csv.gz', 'CSV', 'x String', 'AUTO'). Имена кодеков, такие как GZIP, и раньше принимались без учёта регистра; теперь эти две специальные подсказки ведут себя так же. #113631 (groeneai).
  • Исправлено чтение столбца Tuple, первый элемент которого равен NULL, в форматах CustomSeparated, Regexp и Template с правилом экранирования CSV. В этих форматах простой Tuple занимает по одному полю на каждый элемент, поэтому начальное поле \N относится к этому элементу, а не ко всему столбцу. Ранее оно воспринималось как значение всего столбца, из-за чего поля остальных элементов смещались на следующие столбцы, и CustomSeparated не мог прочитать собственный вывод. #114471 (groeneai).
  • Исправлена ошибка входного формата Regexp, из-за которой неразобранный остаток совпавшего поля молча отбрасывался и вместо сообщения об ошибке сохранялось усечённое или вымышленное значение: при правиле JSON значение v=-1 в UInt64 читалось как 0, а v=2020-01-01junk в Date — как 1975-07-14. Теперь некорректные поля отклоняются при правилах Escaped, CSV и JSON, как и в соответствующих форматах, на поведение которых эти правила, согласно документации, ориентируются. При правиле Raw совпавшее поле, содержащее символ табуляции, теперь читается целиком, а не обрезается на этом символе. #114520 (groeneai).
  • Исправлена логическая ошибка Inconsistent AST formatting (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами) для выражений CREATE INDEX / CREATE HYPOTHETICAL INDEX, которые не выдерживали цикл «форматирование — разбор — форматирование», например CREATE HYPOTHETICAL INDEX i0 ON t0 ((a())) TYPE a и CREATE INDEX i0 ON t0 ((a, b).1) TYPE minmax. #109175 (groeneai).
  • Исправлена логическая ошибка (Logical error: 'KeyCondition uses PREWHERE output') в ридере Parquet v3, возникавшая, когда ключевое условие на уровне формата ссылалось на столбец, который не читается из файла Parquet. #109267 (groeneai).
  • Исправлено исключение в предопределённом HTTP-обработчике при отсутствии заголовка #108324 (vitlibar).
  • Исправлена возможная ошибка Logical error: 'ReadBuffer is canceled. Can't read from it.', возникавшая, когда построчный входной формат (например, TSV/CSV) не мог разобрать входные данные, а нижележащее чтение уже было отменено (например, из-за некорректного HTTP-чанка или усечённого тела запроса). При формировании подробной диагностики разбора больше не выполняется чтение из отменённого буфера. #109708 (groeneai).
  • Формат Values больше не записывает ошибки разбора в system.errors и system.error_log, когда потоковый разбор успешно переключается на разбор SQL-выражений. #111141 (pamarcos).
  • Исправлена ситуация, когда SYSTEM REFRESH для остановленной таблицы RabbitMQ иногда не обрабатывал накопившиеся в очереди сообщения. REFRESH разрешает ровно один внеочередной цикл стриминга, однако этот цикл мог сразу завершиться без строк, поскольку цикл доставки AMQP только что был асинхронно запущен; в результате единственное разрешение расходовалось впустую, а сообщения оставались необработанными до следующего SYSTEM START. #111480 (groeneai).
  • Исправлена ситуация, когда таблица NATS с заданным nats_stream после перезапуска сервера NATS молча переставала получать сообщения. Теперь подписка JetStream восстанавливается автоматически, без необходимости выполнять DETACH TABLE и ATTACH TABLE. #112828 (groeneai).
  • Чрезмерно большое значение kafka_num_consumers теперь отклоняется с понятной ошибкой, а не приводит к сбою выделения памяти внутри движка таблицы Kafka. Ранее при включённой настройке kafka_disable_num_consumers_limit такое значение вызывало исключение std::length_error. #114764 (alexey-milovidov).
  • Сервер Arrow Flight: теперь принимаются учётные данные аутентификации Basic, закодированные в Base64 без дополнения (padding), которые отправляют клиенты Flight на Go, например драйвер ADBC Flight SQL; кроме того, при некорректном заголовке authorization возвращается полноценная ошибка аутентификации вместо общей ошибки Unexpected error in RPC handling. #115085 (alexey-milovidov).
  • Сервер Arrow Flight: теперь отклоняются некорректные учётные данные Basic-аутентификации, в которых отсутствует разделитель между именем пользователя и паролем. #115347 (alexey-milovidov).

Исправления в типах данных, функциях и сериализации

  • Исправлена логическая ошибка Stream <col>.variant_discr ... is not found (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами), возникавшая, когда ALTER TABLE ... MODIFY COLUMN меняет тип столбца на тип с динамическими подстолбцами (например, Variant на Dynamic) в таблице с частями формата Wide, а затем эта часть читается или участвует в слиянии. #110204 (groeneai).
  • Исправлено чтение подстолбца столбца Nullable(Tuple(...)), элемент которого имеет тип LowCardinality(T) без поддержки NULL, если тот же запрос также читает родительский подстолбец. В части формата Compact родительский подстолбец возвращал неверные значения, запрос завершался ошибкой Unexpected return type from assumeNotNull или сервер аварийно завершался из-за защитной проверки string_view: извлечённый подстолбец десериализовался в буфер LowCardinality(Nullable(T)), подпотоки которого затем совместно использовались при чтении родительского подстолбца. #112232 (groeneai).
  • Исправлены ошибка LOGICAL_ERROR «Not-ready Set is passed as the second argument for function globalNullIn» и потеря исходного сообщения об ошибке запроса. Это могло происходить, когда при отсечении частей на основе статистики во время анализа индексов спекулятивно выполнялся подзапрос IN/GLOBAL IN и этот подзапрос завершался ошибкой. #114121 (groeneai).
  • Исправлена ошибка Cannot read all data of type FixedString при чтении подстолбца product_quantization_codebook столбца с кодеком Quantized('product', ...). Кодовая книга каждой части записывается после данных всех гранул и потому не ограничена метками, поэтому при чтении с диапазоном меток, заканчивающимся до последней метки части, она могла быть прочитана не полностью. #112818 (alexey-milovidov).
  • Для значений Map внутри столбца Dynamic больше не записываются части, структура Map которых противоречит их собственным метаданным. Таблицы, отличающиеся только параметром map_serialization_version, совместно использовали один кэшированный объект сериализации, поэтому часть могла получить структуру Map basic, хотя в её метаданных была указана with_buckets, и последующее чтение завершалось ошибкой LOGICAL_ERROR: Stream ...buckets_info ... is not found. Части, уже записанные таким образом предыдущими версиями, остаются нечитаемыми и подлежат удалению. #113514 (groeneai).
  • Исправлена ошибка, из-за которой кодеки ALP, FPC и GCD не учитывали в своём хеше параметр, производный от типа. В части формата Compact механизм записи использует один сжатый поток на каждый уникальный хеш кодека, поэтому два столбца с разной шириной значений и одним и тем же кодеком конфликтовали и совместно использовали один объект кодека с неверной шириной. В результате при несовпадении ширин корректные вставки отклонялись с ошибкой CANNOT_COMPRESS, а в остальных случаях один из столбцов сжимался хуже, чем следовало. #114189 (groeneai).
  • Исправлено некорректное отсечение по индексу, когда ключ сортировки таблицы оборачивает столбец Date в toDateTime (например, ORDER BY toDateTime(date_column)), а запрос фильтрует по исходному столбцу с помощью сравнения вида WHERE date_column >= '...'. toDateTime(Date) переполняется для значений Date за пределами диапазона DateTime (после 2106-02-07), поэтому сохранённый ключ немонотонен. ClickHouse больше не использует отсечение по первичному ключу для такой комбинации ключа и предиката, так как это могло привести к пропуску гранул с подходящими строками. #101814 (nihalzp).
  • Исправлен сбой ALTER MODIFY COLUMN при преобразовании столбца Nullable с DEFAULT в другой тип (например, Nullable(UInt8) → String,LowCardinality(String) или Array(UInt8)). #102156 (il9ue).
  • Исправлено некорректное экранирование SQL-литералов в StorageSQLite и табличной функции sqlite() при передаче предикатов WHERE в SQLite: одинарные кавычки и управляющие символы (\n, \r, \t, \) экранировались обратной косой чертой, которую SQLite не интерпретирует, что приводило к синтаксическим ошибкам или неверным результатам запросов. Также исправлено экранирование строковых литералов, передаваемых в PostgreSQL: строки, вложенные в списки IN, сохраняли экранирование ClickHouse, а управляющие символы отправлялись в виде последовательностей с обратной косой чертой, которые PostgreSQL интерпретирует как другие байты. #104217 (tiandiwonder).
  • Исправлено исключение NOT_FOUND_COLUMN_IN_BLOCK в запросах INNER JOIN ... ON arrayJoin(...) = ..., возникавшее, когда включена настройка query_plan_convert_join_to_in, а SELECT ссылается на исходный столбец типа Array. #104809 (tiandiwonder).
  • Исправлена работа выражений IN и NOT IN с неконстантными правыми операндами, ссылающимися на столбцы текущей строки; обработка правого операнда-кортежа в новом анализаторе приведена в соответствие с существующей семантикой IN в ClickHouse. В старом анализаторе исходный столбец в качестве правого операнда (x IN (arr)) по-прежнему разрешается как имя таблицы и остаётся вне области видимости. #104993 (niyue).
  • Исправлен JOIN с таблицами EmbeddedRocksDB, Redis и KeeperMap, который мог без каких-либо предупреждений возвращать пустой результат при использовании DirectKeyValueJoin с ключами типа String или Nullable(String). #105253 (vdimir).
  • Исправлена ошибка LOGICAL_ERROR (“Unexpected expression in JOIN ON section. Expected boolean (UInt8), got ‘Nothing’”), возникавшая, когда предикат неэквисоединения JOIN ... ON ссылается на столбец типа Nothing, например полученный с помощью ARRAY JOIN []. #106981 (groeneai).
  • Исправлена логическая ошибка Inconsistent AST formatting, которая могла приводить к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами, если лямбда-выражение с псевдонимом использовалось как операнд оператора доступа (элемент кортежа .N или элемент массива []) не на первой позиции списка выражений, например SELECT 1, ((p0, p1) -> p0 AS a7).4[3] FROM t. #107092 (groeneai).
  • Кластерная табличная функция (urlCluster, fileCluster, s3Cluster, …), вложенная в другой распределённый запрос, например clusterAllReplicas(..., urlCluster(...)), теперь отклоняется с ошибкой BAD_ARGUMENTS, а не завершается логической ошибкой (Distributed task iterator is not initialized). #107107 (groeneai).
  • Исправлен сбой табличной функции values с ошибкой ARGUMENT_OUT_OF_BOUND при использовании десятичного литерала, который не может быть точно представлен в столбце с плавающей запятой меньшей точности (например, 0.1 для столбца Float32): SELECT * FROM values('x Float32', 0.1). Теперь такие значения принимаются и преобразуются в ближайшее представимое значение — так же, как в CAST и INSERT ... VALUES. #108055 (alexey-milovidov).
  • Исправлена потеря LowCardinality в типах ключей и значений Map функциями mapFilter, mapSort (и её вариантами) и mapConcat. Ранее mapFilter для столбца Map(LowCardinality(String), String) возвращала Map(String, String), что могло повредить метаданные таблицы, созданной через CREATE TABLE ... AS SELECT, и приводить к сбою CHECK TABLE. #108057 (alexey-milovidov).
  • Исправлена ошибка, из-за которой отменённый или завершённый через KILL запрос INSERT продолжал долго выполняться при построении skip-индекса (например, неограниченного индекса set(0) на столбце с высокой мощностью). Теперь при отмене запроса построение индекса сразу прекращается. #108351 (tiandiwonder).
  • Исправлена ошибка, из-за которой SELECT из табличной функции primes не реагировал на отмену: при большом значении step (или limit) запрос мог ещё долго выполняться после KILL QUERY или тайм-аута. Теперь он сразу прекращается. #108353 (tiandiwonder).
  • Исправлен разбор имён типов данных, содержащих подстроку INT (например, имени в стиле функции, такого как quantileInterpolatedWeighted, указанного на месте типа данных). Такие имена ошибочно принимались за целочисленные типы MySQL, а их первая группа аргументов (...) незаметно поглощалась как модификатор ширины отображения, что могло нарушить обратимость форматирования запроса. #108354 (groeneai).
  • Исправлена несогласованность, из-за которой некорректный ARRAY JOIN, за которым следовали запятая и список таблиц в скобках, ошибочно разбирался как перекрёстное соединение, а не отклонялся. #108365 (Algunenano).
  • Исправлено исключение LOGICAL_ERROR (“Invalid action query tree node …”), возникавшее, когда распределённый запрос одновременно выполнял дедупликацию структурно идентичных дублирующихся столбцов ALIAS и обращался к табличной функции с аргументом именованной коллекции вида key = value (например, oss(s3_conn, filename = '...')). #108435 (groeneai).
  • Исправлена логическая ошибка (исключение в релизных сборках, аварийное завершение сервера в отладочных сборках и сборках с санитайзерами), которая могла возникать при вызове функции с несколькими аргументами LowCardinality над distributed таблицей, например при использовании concatAssumeInjective((SELECT toLowCardinality('p')), s) в качестве ключа GROUP BY с remote(). Выдавались сообщения Default functions implementation for LowCardinality is supported only with a single LowCardinality argument или Expected the argument ... to have N rows, but it has M. #108871 (groeneai).
  • Исправлена ошибка, из-за которой настройка use_client_time_zone игнорировалась для строковых литералов DateTime/DateTime64, интерпретируемых на сервере (асинхронный INSERT, литералы в SELECT). Теперь при включённой use_client_time_zone клиент передаёт свой локальный часовой пояс как session_timezone, поэтому разбор на стороне сервера работает так же, как при синхронном INSERT. #109051 (groeneai).
  • Исправлена ошибка, из-за которой max_execution_time (с timeout_overflow_mode = 'throw') иногда так и не отменял запрос: если внутренний отслеживатель тайм-аутов уже ожидал запрос с более поздним сроком, то зарегистрированный позже запрос с более ранним сроком мог быть полностью пропущен и выполняться намного дольше установленного лимита времени. #109792 (tiandiwonder).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK, возникавшая при включённом анализаторе, когда запрос к таблице Distributed использовал вместе с ORDER BY столбец _shard_num (или shardNum()), ставший Nullable (например, при FULL JOIN с join_use_nulls = 1). #109798 (groeneai).
  • Исправлена ошибка NOT_IMPLEMENTED (“Method getDataAt is not supported for Nullable(String)”), которая могла возникать при JOIN с enable_join_runtime_filters = 1 (включено по умолчанию начиная с версии 26.2), если ключ JOIN на стороне построения имел тип LowCardinality(Nullable(...)) и содержал NULL, а runtime-фильтр переключался на свой bloom-фильтр. #109824 (groeneai).
  • Исправлено аварийное завершение сервера при передаче лямбда-выражения туда, где функция высшего порядка ожидает конкретное значение (например, в качестве аккумулятора arrayFold, как в arrayFold(lambda, arr, another_lambda)). Теперь при enable_analyzer = 0 такие запросы отклоняются с ошибкой ILLEGAL_TYPE_OF_ARGUMENT, а не приводят к аварийному завершению. #109840 (groeneai).
  • Псевдоним unnest для arrayJoin теперь запрещён в фильтрах ROW POLICY. Это закрывает лазейку, из-за которой такая политика могла вызывать логическую ошибку column->size() == num_rows при чтении. #109973 (Algunenano).
  • Исправлена ситуация, когда индексы пропуска данных, определённые на подстолбцах Tuple, не использовались при обращении к полю через tupleElement(t, 'name'), tupleElement(t, N) или t.N, если в том же запросе считывался и весь кортеж (например, SELECT *). Теперь все эти формы отсекают гранулы так же, как обращение к именованному подстолбцу t.name. #110056 (groeneai).
  • Исправлена ошибка BAD_GET при сравнении столбца Array(String) с литералом массива (arr = ['x']), если у столбца есть индекс пропуска данных text, tokenbf_v1 или ngrambf_v1. Теперь индекс обрабатывает такое сравнение как полное сканирование, и весь запрос больше не завершается ошибкой. #110057 (groeneai).
  • Исправлена ложная ошибка ILLEGAL_COLUMN в ALTER TABLE ... ADD COLUMN IF NOT EXISTS, возникавшая, если на этапе применения столбец уже существовал. Это происходило, когда один и тот же столбец добавлялся дважды с IF NOT EXISTS в одной инструкции или когда параллельный ALTER добавлял столбец между фазами подготовки и применения. #110080 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Bad cast from type ColumnLowCardinality to ColumnString), возникавшая, когда identity() (или результат скалярного подзапроса) оборачивает значение, содержащее вложенный LowCardinality, а в запросе используется WITH TOTALS/WITH ROLLUP. #110138 (groeneai).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK при использовании GROUP BY ALL по выражению с кортежем вместе с ORDER BY. #110206 (alexey-milovidov).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK при INSERT в таблицу с ограничением CHECK, ссылающимся на подстолбец (например, x.null столбца Nullable или arr.size0 столбца Array). #110208 (alexey-milovidov).
  • Исправлены неверные результаты запросов, вызванные оптимизацией optimize_and_compare_chain (включена по умолчанию): условие, выведенное по транзитивности из a < b AND b < c, могло использовать иную семантику сравнения, чем исходные условия, если в цепочке смешивались типы с правилами преобразования, зависящими от конкретной пары (например, Enum и String, Decimal и Float64, FixedString разной ширины). Теперь транзитивные условия выводятся только в пределах групп типов с единым порядком сравнения. #110621 (yariks5s).
  • Исправлена ошибка, из-за которой настройка optimize_injective_functions_in_group_by изменяла результаты запроса для GROUP BY GROUPING SETS и GROUP BY ... WITH TOTALS. Согласно документации, эта настройка не влияет на результат, однако исключение инъективной функции от ключа группировки приводило к неверному значению (или к потере строки) в строках, где этот ключ отсутствует в агрегируемом наборе (набор GROUPING SETS, не содержащий ключ), а также в строке WITH TOTALS. Неверное значение могло совпасть с реальным значением ключа, и тогда строку суперагрегата было невозможно отличить от настоящей группы в том же результирующем наборе. #110721 (groeneai).
  • Исправлено зависание сервера при умножении состояния агрегатной функции median/quantile (на основе ReservoirSampler) на очень большую целочисленную константу (например, medianState(x) * 18446744073709551615). Запрос переставал реагировать на отмену и мог выполняться бесконечно. #110779 (groeneai).
  • Исправлено аварийное завершение (разыменование нулевого указателя во время анализа запроса) при вызове getSubcolumn для аргумента типа JSON с именем внутреннего подстолбца-подсказки типа, то есть с именем, начинающимся с маркера типа в виде обратной кавычки. #110940 (groeneai).
  • Исправлена ошибка, из-за которой map[key] возвращал значение последующего дубликата ключа вместо первого. Если столбец Map содержал повторяющиеся ключи, результат map[key] мог зависеть от предыдущих строк в том же блоке и от настройки optimize_functions_to_subcolumns, поэтому SELECT и WHERE для одной и той же строки могли давать разные результаты. #111246 (groeneai).
  • Исправлена логическая ошибка !rhs_literal->getValue().isNull() в оптимизаторе логических выражений, возникавшая, когда в цепочке AND столбец сравнивается с константой со значением NULL, тип которой отличен от Nullable (например, Variant со значением NULL), при use_variant_default_implementation_for_comparisons = 0. #111292 (groeneai).
  • Исправлены неверные результаты запросов с индексом пропуска set и предикатом вида (x AND <null-value>) OR y, где NULL возвращается функцией (например, toInt64OrNull('x'), nullIf(1, 1), CAST(NULL AS Nullable(Int64))). Такое значение оборачивалось в __bitWrapperFunc и распространяло NULL вместо маски «неизвестно», из-за чего индекс set мог отсекать гранулы, на самом деле удовлетворяющие условию, и запрос возвращал меньше строк, чем следовало. #111604 (groeneai).
  • Исправлена ошибка, из-за которой CREATE TABLE/ALTER TABLE с включённым анализатором допускали выражение DEFAULT/MATERIALIZED для столбца, ссылающееся на виртуальный столбец, например _table или _database. Вставка в такую таблицу завершалась ошибкой NOT_FOUND_COLUMN_IN_BLOCK, а столбец MATERIALIZED (значение которого нельзя передать явно) навсегда делал вставку в таблицу невозможной. Теперь такие выражения отклоняются уже на этапе определения — так же, как без анализатора. Столбцы ALIAS (вычисляемые при чтении) и EPHEMERAL (нехранимые входные данные для вставки), использующие виртуальные столбцы, по-прежнему работают. #111776 (groeneai).
  • Исправлена ошибка UNKNOWN_QUERY_PARAMETER при вызове параметризованного представления с аргументом-подзапросом типа Array, Tuple или LowCardinality, например SELECT * FROM v(param = (SELECT groupArray(x) FROM t)). #111790 (groeneai).
  • Исправлены три ошибки в преобразованиях анализатора, которые превращают цепочку сравнений в IN/NOT IN (x = c1 OR x = c2 OR ..., x != c1 AND x != c2 AND ... и has(const_array, x)). Для выражения типа Variant при use_variant_default_implementation_for_comparisons = 0 преобразование меняло тип результата выражения с UInt8 на Nullable(UInt8), из-за чего проверка дерева запроса в отладочных сборках и сборках с санитайзерами выдавала LOGICAL_ERROR. Для выражения с динамической структурой (Dynamic, Array(Dynamic), JSON) после преобразования корректный запрос завершался ошибкой Illegal type ... of argument of function in, поскольку IN не принимает такие аргументы. Кроме того, в обоих случаях возвращались неверные результаты, если константа не преобразуется к типу выражения без потерь, например при сравнении константы DateTime с указанием времени суток со столбцом типа Date. #111924 (groeneai).
  • Исправлена ошибка, из-за которой quantileDeterministic, quantilesDeterministic и medianDeterministic при каждом запуске возвращали разные результаты для одних и тех же данных, если в запросе используются параллельные реплики, distributed таблица или внешняя агрегация, а также если состояния хранятся в таблице (в том числе внутри значения Dynamic). Состояния, записанные до этой версии под старым названием типа без версии, сохраняют прежнее поведение, поскольку их формат изменить нельзя. #112052 (alexey-milovidov).
  • Исправлены неверные результаты, вызванные тем, что запросы векторного поиска засоряли кэш условий запроса. Запрос SELECT ... WHERE <condition> ORDER BY <distance function> LIMIT n к таблице с индексом vector_similarity мог пометить гранулы как не соответствующие <condition>, из-за чего последующий обычный запрос SELECT ... WHERE <condition> к той же таблице молча возвращал меньше строк. Чтение при векторном поиске больше не записывает данные в кэш условий запроса. #112086 (groeneai).
  • Исправлена потеря настройки serialize_string_in_memory_with_zero_byte в сериализованном плане запроса. При serialize_query_plan = 1 в кластере, где эта настройка отключена, строковое представление в памяти могло различаться на инициаторе и на узле, выполняющем десериализованный план: настройка считывалась при десериализации, но не записывалась при сериализации, поэтому на выполняющем узле всегда принимала значение по умолчанию. #112131 (groeneai).
  • Исправлен неверный результат для JOIN, выражение ON которого содержит константный конъюнкт, например ON l.id = r.id AND CAST(NULL AS Nullable(UInt8)). Оптимизация плана запроса молча отбрасывала константу, и JOIN выполнялся так, будто её нет: соединения INNER, LEFT SEMI и RIGHT SEMI возвращали совпавшие строки, хотя при заведомо ложном условии результат должен быть пустым, а RIGHT ANTI не возвращал ни одной строки вместо всех. #112155 (vdimir).
  • Исправлены неверные результаты при вызове параметризованного представления с аргументом, который не является присваиванием вида parameter = value. При enable_analyzer = 0, а также в EXPLAIN SYNTAX с настройками по умолчанию вызовы вроде pv(concat(name, '!')), pv(name, 'a'), pv(name != 'a') и pv(tuple(name = 'a')) молча связывали параметр представления с посторонним выражением, вместо того чтобы выдавать ошибку UNKNOWN_QUERY_PARAMETER, как это делает анализатор. Теперь такие вызовы одинаково отклоняются в обоих путях выполнения. #112194 (groeneai).
  • Исправлена ошибка, из-за которой CREATE VIEW или CREATE FUNCTION, в определении которых вызываются substr, mid или byteSlice в форме, которую грамматика substring не может повторно разобрать, принимались, но записываемые ClickHouse метаданные не являлись корректным SQL. Последующее чтение такого определения завершалось ошибкой SYNTAX_ERROR, а при запуске сервера прерывало загрузку метаданных, так что сервер вообще не мог запуститься. Теперь такие определения поддерживают обратимый обмен, а существующие файлы метаданных вида substring(x, a, b, c) снова читаются, поэтому затронутый сервер запускается без ручного вмешательства. #112195 (groeneai).
  • Исправлены неверные результаты, неправильный порядок вывода ORDER BY и исключение BAD_TYPE_OF_FIELD в случаях, когда первичный ключ имеет тип Array или Tuple, а запрос применяет к нему plus, minus, multiply, divide или intDiv. Арифметические операции над составным значением выполняются поэлементно, а составные значения сравниваются лексикографически, поэтому анализ первичного ключа больше не считает такое выражение монотонным. #112339 (groeneai).
  • Исправлена ошибка Code: 62 ... You must not specify ANY or ALL for PASTE JOIN. (SYNTAX_ERROR), которую выдавал удалённый сервер для запроса с PASTE JOIN, передаваемого на другой сервер, например когда левая таблица является таблицей Distributed или табличной функцией *Cluster. Модуль форматирования выводил ALL PASTE JOIN — запись, которую парсер отвергает, поэтому принимающий сервер не мог разобрать полученный запрос. #112404 (groeneai).
  • Исправлена ошибка, из-за которой список псевдонимов столбцов, например (SELECT 1) AS t(x) или WITH t(x) AS (SELECT 1), не был виден внутри табличной функции view: обращение к t.x завершалось ошибкой UNKNOWN_IDENTIFIER, хотя та же конструкция работает вне view. #112690 (groeneai).
  • Исправлена логическая ошибка при форматировании запроса, когда предложение ARRAY JOIN не содержит выражений. Теперь такое предложение отклоняется ещё на этапе разбора с ошибкой SYNTAX_ERROR — так же, как пустой USING, — а не принимается и форматируется в текст, который невозможно разобрать обратно. #112699 (groeneai).
  • Исправлена ошибка, из-за которой connectionId выбрасывал Context has expired, если действия выражения, подготовленные для подзапроса, выполнялись после освобождения контекста, в котором они были построены. #112870 (clickgapai).
  • Исправлены логическая ошибка и неверные результаты в случаях, когда условие JOIN ON не на равенство, вычисляемое во время JOIN, содержит arrayJoin. Теперь JOIN с алгоритмами hash, parallel_hash или grace_hash отклоняет такое условие с ошибкой INVALID_JOIN_ON_EXPRESSION. Если развёртывание массива зависит только от одной стороны, перенесите его в ARRAY JOIN в подзапросе перед JOIN; условие, в котором аргумент arrayJoin читает столбцы с обеих сторон, придётся переписать. #112889 (groeneai).
  • Исправлена ошибка, из-за которой geohashesInBox тратила неограниченное время на область нулевой площади, например geohashesInBox(0., 0., 180., 0., 12). Такой запрос возвращал правильный единственный geohash, но выполнял около 5e8 холостых итераций цикла на строку и игнорировал как max_execution_time, так и KILL QUERY. #112976 (groeneai).
  • Изменение SETTINGS, помеченное как записанное без значения, теперь отклоняется, если оно содержит значение, отличное от true; кроме того, при форматировании запроса значение такого изменения больше никогда не опускается. Ранее специально сформированный JSON-фрагмент AST мог выполнить настройку типа Bool со значением false, тогда как system.query_log и formatQueryFromJSON показывали форму без значения. #113025 (alexey-milovidov).
  • Исправлена ошибка UNKNOWN_IDENTIFIER при выборке из VIEW, у которого объявленные типы столбцов отличаются от типов, возвращаемых его внутренним запросом, например SELECT sum(length(arr)) FROM v, где v объявляет arr Array(UInt8) поверх столбца String. При значении по умолчанию optimize_functions_to_subcolumns = 1 оптимизатор переписывал length(arr) в чтение подстолбца arr.size0 и передавал это имя во внутренний запрос, в котором такого подстолбца нет. #113057 (groeneai).
  • Исправлена отмена чтения через табличную функцию postgresql и движок PostgreSQL. Отмена на этапе запуска чтения могла приводить к гонке на указателе транзакции, а сама отмена могла полностью теряться, из-за чего запрос продолжал выполняться, пока PostgreSQL не завершал его. Отмена, поступившая в PostgreSQL до начала выполнения оператора COPY, по-прежнему может быть отброшена. #113150 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Next task callback is not set for query), возникавшая, когда представление с SQL SECURITY DEFINER или SQL SECURITY NONE поверх кластерной табличной функции (s3Cluster, urlCluster, fileCluster) читалось как вторичный запрос, например через remote или clusterAllReplicas. Теперь такая неподдерживаемая вложенность отклоняется с обычной ошибкой запроса, а не приводит к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами. #113371 (groeneai).
  • Исправлена логическая ошибка IDENTIFIER is not a table expression, возникавшая, когда табличная функция семейства remote с аргументом view(...) использовалась в левой части JOIN ... USING, ключом которого является псевдоним из списка SELECT, при analyzer_compatibility_join_using_top_level_identifier = 1. #113400 (groeneai).
  • Исправлена ошибка Not-ready Set is passed as the second argument for function 'in', возникавшая, когда запрос фильтровал system.databases по столбцу name с подзапросом внутри indexHint, например SELECT count() FROM system.databases WHERE indexHint(name IN (SELECT 'foo')). Такой запрос отклонялся с ошибкой LOGICAL_ERROR в релизных сборках и приводил к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами. #113556 (groeneai).
  • Исправлена ошибка, из-за которой запрос по столбцу Variant игнорировал max_execution_time и KILL QUERY. При вызове функции с несколькими аргументами Variant функция разрешалась отдельно для каждой альтернативы каждого аргумента, и ни один из двух циклов, выполняющих эту работу, не проверял отмену, поэтому такой запрос невозможно было остановить до его завершения. #113612 (groeneai).
  • Исправлен сбой ALTER TABLE ... MODIFY COLUMN с ошибкой Cannot specify codec for column type ALIAS, когда один оператор одновременно превращает столбец ALIAS в физический (DEFAULT или MATERIALIZED) и задаёт CODEC. #113853 (groeneai).
  • Исправлено аварийное завершение сервера при JOIN с константным выражением ON, когда правая часть содержит ARRAY JOIN. При чтении лениво реплицируемого столбца правой части использовался уже освобождённый ColumnReplicated. #113901 (groeneai).
  • Исправлена утечка памяти при optimize_aggregation_in_order = 1, возникавшая, когда ключ сортировки таблицы является строгим префиксом ключа GROUP BY и используется агрегатная функция, состояние которой владеет памятью в куче, например quantileDD. Потребление памяти сервером росло с каждым таким запросом вплоть до перезапуска. #114010 (groeneai).
  • Исправлена ошибка, из-за которой isProbablePrime для UInt128/UInt256 игнорировала max_execution_time и KILL QUERY. Блок широких значений обрабатывался целиком в рамках одного вызова функции без точки отмены, поэтому запрос мог выполняться ещё несколько минут после истечения отведённого времени. #114032 (groeneai).
  • Исправлена ошибка Code: 46. DB::Exception: Unknown function exists. (UNKNOWN_FUNCTION), возникавшая, когда предложение PREWHERE содержит предикат IN (subquery) и задана настройка rewrite_in_to_join = 1 (или make_distributed_plan = 1, которая принудительно её включает). Тот же запрос с WHERE выполнялся корректно. #114067 (RohithPariki).
  • Исправлена ошибка LOGICAL_ERROR в arrayAutocorrelation, возникавшая, когда аргументом является непустой массив с типом элементов Nothing, например SELECT arrayAutocorrelation([arrayMax([])]). Теперь такой аргумент отклоняется с ошибкой ILLEGAL_COLUMN. Литерал пустого массива [] по-прежнему возвращает []. #114249 (groeneai).
  • CREATE TABLE и ALTER TABLE теперь запрещают использовать кодеки сжатия с потерями, такие как SZ3, для столбцов, входящих в ключ сортировки. #114531 (groeneai).
  • Исправлен бесконечный неотменяемый цикл в функциях hop и windowID, возникавший, когда длительность аргумента-интервала в секундах кратна 2^32 (например, toIntervalDay(2147483648)): из-за переполнения при вычитании проверка выхода времени за допустимые пределы не срабатывала, а при постоянных аргументах цикл выполнялся на этапе анализа, где запрос нельзя было даже завершить. Тот же интервал мог также бесконечно нагружать фоновый поток WINDOW VIEW; теперь такое оконное представление отклоняется при создании. #114607 (alexey-milovidov).
  • Исправлена логическая ошибка Not-ready Set is passed as the second argument for function 'in' для запроса с подзапросом IN, читающим данные с удалённого кластера: теперь запрос завершается с фактической ошибкой подзапроса, например ошибкой соединения. #114983 (alexey-milovidov).
  • Исправлена проблема с INSERT в таблицу Log, TinyLog или StripeLog, завершавшимся сбоем при фиксации записанных размеров файлов. Такая вставка могла оставить свои строки в таблице, несмотря на сообщение об ошибке, либо привести к рассогласованию файлов данных столбца типа Array. Чтение таблицы Log или TinyLog, в которой столбец типа Array не содержит элементов, хотя смещения указывают на их наличие, теперь завершается ошибкой с указанием имени столбца, а не чтением за пределами элементов. Частично записанный столбец элементов отклонялся и ранее. #115027 (groeneai).
  • Исправлена ошибка TYPE_MISMATCH (“CAST AS Array can only be performed between same-dimensional array types”) для запроса с константой типа Array(Map(...)), например has([map('k', 'v')], m), выполняемого над таблицей Distributed или с параллельными репликами. #115883 (alexey-milovidov).
  • Исправлены неверные результаты при JOIN с представлением или view(), у которого проецируемый столбец имеет то же имя, что и столбец одного из его собственных внутренних отношений, например SELECT expr(x.c0) AS c0 FROM a AS x, b AS y. Оптимизатор порядка JOIN встраивал такое выражение в развёрнутый граф JOIN, а затем применял его дважды, из-за чего запрос без каких-либо предупреждений возвращал искажённые значения. Если выражение к тому же меняло тип столбца, по той же причине на этапе построения плана возникала ошибка AMBIGUOUS_COLUMN_NAME. #116152 (groeneai).
  • Исправлено исключение в коррелированных подзапросах, возникавшее, когда внешние столбцы становятся Nullable при group_by_use_nulls с ROLLUP/CUBE. #100365 (alexey-milovidov).
  • Значение max_replication_lag_to_enqueue = 0 теперь отклоняется для баз данных Replicated. При этом значении проверка несинхронизированности после восстановления всегда оказывалась истинной, что приводило к аварийному завершению сервера с LOGICAL_ERROR в отладочных сборках и сборках с санитайзерами. Теперь 0 отклоняется на этапе разбора с ошибкой BAD_ARGUMENTS независимо от источника (CREATE DATABASE ... SETTINGS, блок <database_replicated> в конфигурации сервера, повторное применение ATTACH и повторное применение существующих метаданных при обновлении). Минимальное допустимое значение — 1. #106006 (groeneai).
  • Запрещено создание индекса пропуска minmax для столбцов JSON (Object), чтобы предотвратить исключение NO_COMMON_TYPE при вставке массивов со смешанными типами. Вместо этого используйте типизированные подстолбцы (например, INDEX idx json.field TYPE minmax). #106094 (linhaojie).
  • Исправлена ошибка, из-за которой JSON_QUERY/JSON_VALUE/JSON_EXISTS возвращали Dynamic вместо String/UInt8 для аргументов типа Dynamic. #106877 (Avogar).
  • Исправлено переполнение знакового целого при установке очень большого значения для настройки тайм-аута ожидания, например interactive_delay: ожидание могло сразу завершаться по тайм-ауту, а сервер — аварийно завершаться под Undefined Behavior Sanitizer. #106961 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR («Unsupported argument types») в функции geohashesInBox, возникавшая, когда в аргументах-координатах смешивались константные и неконстантные значения или когда координата имела тип BFloat16. Смешанные константные и неконстантные аргументы Float32 теперь работают корректно, а аргументы BFloat16 отклоняются с понятным сообщением об ошибке. #107063 (groeneai).
  • Исправлена ошибка, из-за которой заголовок в форматах CSVWithNames и CSVWithNamesAndTypes содержал меньше столбцов, чем данные, при включённой настройке output_format_csv_serialize_tuple_into_separate_columns (включена по умолчанию). Теперь заголовок (и строка типов) разворачивает столбцы Tuple в конечные поля с именами через точку (например, t.a, t.b), поэтому число столбцов в заголовке совпадает с данными. Это поведение управляется новой настройкой output_format_csv_header_serialize_tuple_into_separate_columns (по умолчанию 1); чтобы вернуть прежний заголовок с одним именем, установите её в 0. #107371 (groeneai).
  • Исправлена утечка памяти во встроенном mongo-c-driver, которая могла возникать при чтении из MongoDB (например, через словарь MongoDB или табличную функцию mongodb), если после ошибки чтения, допускающей повтор, не удавалось выбрать сервер для повторной попытки. #107448 (groeneai).
  • Исправлены логическая ошибка (WhichDataType(const_type).isArray()) и аварийное завершение сервера при анализе первичного ключа, когда pointInPolygon вызывается с константным аргументом-полигоном оберточного типа, такого как Variant или Dynamic (например, pointInPolygon((x, y), if(c, [(0, 0), ...], NULL))). #107589 (groeneai).
  • Исправлены логические ошибки (Bad cast), вызванные несогласованным удалением LowCardinality, вложенного в столбцы Variant и Dynamic, например в concat, format и при анализе первичного ключа. #107773 (Avogar).
  • Исправлен разбор параметров команды исполняемых пользовательских функций: плейсхолдеры с пустыми или недопустимыми именами больше не принимаются в качестве параметров. #107983 (goutamadwant).
  • Исправлена работа accurateCastOrNull для Tuple, элемент которого имеет тип Dynamic/Variant: настоящий NULL в исходных данных воспринимался как ошибка преобразования. Если целевой элемент имеет тип Nullable, исходный NULL теперь сохраняется как NULL в этом элементе (так же, как для обычного исходного Tuple(Nullable(...))); если целевой элемент не Nullable, исходный NULL теперь превращает в NULL весь кортеж (как в эталонном поведении без Dynamic), а не подставляет значение элемента по умолчанию. При ошибках разбора и переполнения весь кортеж, как и раньше, становится NULL. #108023 (groeneai).
  • Табличная функция mongodb теперь принимает oid_columns, переданный как именованный аргумент (например, oid_columns='_id'), и больше не отклоняет его с ошибкой BAD_ARGUMENTS. #108039 (alexey-milovidov).
  • Теперь можно выполнять запросы к словарю range_hashed или complex_key_range_hashed с диапазоном типа DateTime64, Decimal или с плавающей запятой, передавая соответствующий аргумент в dictGet/dictHas. Ранее такие запросы завершались ошибкой must be convertible to Int64, а для открытых интервалов диапазонов Decimal/DateTime64 ошибочно возвращалось значение по умолчанию. #108052 (alexey-milovidov).
  • Исправлено аварийное завершение сервера (Logical error в IColumn::insertFrom) при приведении Array(Dynamic) или Array(Variant) к QBit с помощью accurateCastOrNull, например accurateCastOrNull(CAST(range(114), 'Array(Dynamic)'), 'QBit(Float32, 114)'). #108288 (groeneai).
  • Исправлен сбой сервера (Received signal 4, недопустимая инструкция), который мог возникать из-за некорректного или рассинхронизированного потока собственного TCP-протокола. Теперь перед разбором поля initial_address в ClientInfo проверяется, что оно имеет числовой формат host:port; раньше нечисловой порт мог попасть в перехватываемую функцию libc getservbyname. #108410 (groeneai).
  • Исправлено чрезмерное выделение памяти при десериализации специально сформированных состояний агрегатных функций mannWhitneyUTest, rankCorr, largestTriangleThreeBuckets, quantileGK, sequenceMatch/sequenceCount и groupArrayIntersect. Некорректное состояние могло указывать огромное количество элементов, из-за чего сервер пытался выделить десятки гигабайт, получив на вход всего несколько байт; теперь такие состояния отклоняются с ошибкой TOO_LARGE_ARRAY_SIZE. #108465 (groeneai).
  • Исправлена логическая ошибка (Bad cast from type DB::ColumnNullable to DB::ColumnString) и возможные неверные результаты при использовании group_by_use_nulls с константным ключом группировки типа LowCardinality в GROUPING SETS/ROLLUP/CUBE. #108771 (alexey-milovidov).
  • Исправлена ошибка TYPE_MISMATCH в mapFilter, mapSort, mapReverseSort, mapPartialSort и mapConcat, возникавшая, когда значение Map содержит вложенный Map с LowCardinality, например mapFilter((k, v) -> 1, map('a'::LowCardinality(String), map('x'::LowCardinality(String), 'y'))). #108798 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (“Inconsistent AST formatting”), которая приводила к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами при форматировании типа данных Tuple, сочетающего именованные и безымянные элементы (например, Tuple(a UInt8, UInt16)). #108915 (groeneai).
  • JSONExtract теперь учитывает cast_string_to_date_time_mode при преобразовании строковых значений JSON в DateTime/DateTime64 — так же, как CAST. #109252 (Utkal059).
  • Исправлено поведение IN со столбцом-массивом в качестве правого аргумента: раньше без каких-либо предупреждений возвращался неверный (всегда ложный) результат или выбрасывалось исключение. Теперь x IN arr работает как has(arr, x). #109416 (alexey-milovidov).
  • Исправлена ошибка LOGICAL_ERROR в arrayFold с неконстантным аргументом Array(LowCardinality(T)) (например, arrayFold((acc, x) -> acc + x, materialize([1, 2, 3]::Array(LowCardinality(Int64))), toInt64(0))): вызов завершался ошибкой “Arguments of ‘plus’ have incorrect data types” (а в отладочных сборках и сборках с санитайзерами — аварийным завершением сервера). #109462 (groeneai).
  • Исправлено исключение ILLEGAL_COLUMN в conv: теперь аргументы FixedString корректно приводятся к String. #109771 (hp77-creator).
  • Исправлены неверные результаты при чтении через табличные функции с FINAL / SAMPLE при serialize_query_plan = 1, а также ключ кэша статистики хеш-таблицы агрегации для табличных функций (ранее все табличные функции использовали одну общую запись для предварительного выделения памяти). #109847 (azat).
  • Исправлен разбор числовых значений 1/0 как значений Bool внутри составных типов (например, Array(Bool), Tuple(Bool, ...)). Ранее разбор [1,0] завершался ошибкой CANNOT_READ_ARRAY_FROM_TEXT, тогда как [true,false] обрабатывался корректно. #109976 (groeneai).
  • Исправлена ошибка NOT_IMPLEMENTED (Method getDataAt is not supported for Nullable(String) in case if value is NULL), возникавшая, когда индекс text построен на Array(LowCardinality(Nullable(String))) (включая хранящиеся таким образом поля Nested), а индексируемый массив содержит элемент NULL. Теперь элементы массива со значением NULL пропускаются при построении индекса — так же, как для Array(Nullable(String)). #110055 (groeneai).
  • Исправлены некорректные результаты subBitmap, bitmapSubsetInRange и bitmapSubsetLimit для битмапов, всё ещё хранящихся в компактном представлении, в том числе для значений элементов UInt64 и Int64 больше 2^32, которые усекались до 32 бит. Сравнения в функциях для битмапов со знаковыми типами элементов теперь единообразно используют беззнаковое значение типа элемента: например, в битмапе Int8 элемент -1 сравнивается как 255, а не как расширенное со знаком значение 4294967295. Это также исправляет работу bitmapMin, bitmapMax, bitmapContains и bitmapTransform для битмапов, вышедших за пределы компактного представления. Запросы, в которых передавались пороговые значения, расширенные со знаком, необходимо скорректировать: для битмапа Int8 вызов bitmapSubsetInRange(bm, 4294967168, 4294967296) следует заменить на bitmapSubsetInRange(bm, 128, 256). Кроме того, исправлены ошибки, из-за которых groupNumericIndexedVector возвращала для индексных столбцов Int8 и Int16 иные результаты, чем для более широких типов индексов, а numericIndexedVectorGetValue возвращала 0 для отрицательных индексов. Исправлена документация по функциям для битмапов, в том числе описание функций выделения подмножеств, для которых ошибочно указывалась индексация с 1, а также описание поддержки знаковых типов в bitmapBuild / bitmapToArray. #110072 (RamiDarwiche).
  • Устранены участки кода с неопределённым поведением при знаковом переполнении в интервальной арифметике для WITH FILL STEP с интервальным шагом и для функций интервалов даты и времени add* / subtract* с экстремальными приращениями: теперь экстремальные значения интервалов обрабатываются детерминированно, без расчёта на знаковое переполнение. Также исправлено зависание WITH FILL с интервальным шагом при очень большом шаге YEAR, из-за которого календарь ранее шёл в обратную сторону. #110158 (groeneai).
  • Исправлен квадратичный рост времени выполнения (и игнорирование max_execution_time) при агрегации в порядке сортировки (aggregation in order) с группировкой по нескольким ключам, когда порядок сортировки совпадает лишь с префиксом ключа группировки. #110159 (alexey-milovidov).
  • Исправлены сравнения, которые ранее завершались ошибкой ILLEGAL_TYPE_OF_ARGUMENT, если у операндов нет наименьшего общего супертипа. Массивы, например Array(Int64) и Array(UInt64) или Array(Int256) и Array(UInt256), теперь можно сравнивать лексикографически с помощью =, !=, <, <=, >, >=, IS DISTINCT FROM и IS NOT DISTINCT FROM. Безопасные для NULL сравнения, такие как isDistinctFrom / isNotDistinctFrom, теперь также сравнивают поддерживаемые пары числовых или десятичных значений (не массивов) по значению, вместо того чтобы завершаться ошибкой. Кроме того, сравнения на равенство теперь работают для массивов с вложенными элементами Tuple(Nullable(...)). #110245 (diegomestre2).
  • Исправлено переполнение знакового целого (UBSan) при преобразовании экстремального значения DateTime64 (например, INT64_MIN) в Time/Time64 в часовом поясе с отрицательным смещением. #110451 (groeneai).
  • Преобразование выходящих за допустимый диапазон значений с плавающей запятой (BFloat16, Float32, Float64) и значений UInt64, превышающих Int64::max(), в DateTime и Time теперь на всех архитектурах надёжно ограничивается границами диапазона (ранее результат такого преобразования зависел от архитектуры и на x86-64 мог «заворачиваться» при переполнении), а для неконечных значений (NaN, inf) теперь генерируется исключение вместо произвольного результата. То же исправление применено к преобразованию чисел с плавающей запятой в Date в функции toDate, а также к преобразованию UInt64 и широких целых чисел ((U)Int128, (U)Int256) в Date и Date32, которое вместо ограничения могло возвращать день до начала эпохи. Преобразование числа в Time теперь ограничивается диапазоном типа для любого числового исходного типа (ранее значения из узких беззнаковых или широких целочисленных типов сохранялись без ограничения и ограничивались только при выводе), а точное приведение к Time больше не отклоняет отрицательные значения, которые поддерживает Time, и не ограничивает молча значения, которые в него не помещаются. Точное приведение числа к Date32 (accurateCast, accurateCastOrNull) больше не ограничивает молча выходящее за диапазон или неконечное значение, а генерирует исключение или возвращает NULL — так же, как это уже происходило для Date и DateTime; варианты OrDefault для таких входных данных возвращают значение Date32 по умолчанию. Точное приведение нецелого числа с плавающей запятой к Date, Date32, DateTime или Time теперь отклоняется, а не молча усекается. Также исправлена документация функции toDateTime32, в которой по ошибке приводились примеры toDateTime64 и описывался диапазон значений DateTime64. #110459 (alexey-milovidov).
  • Исправлен сбой вывода схемы с ошибкой Map cannot have a key of type LowCardinality(Nullable(String)) при чтении ORC-файлов, в которых ключи map закодированы словарём, — включая ORC-файлы, записанные Spark, и файлы, записанные самим ClickHouse при включённой настройке output_format_orc_dictionary_key_size_threshold. #110492 (tiandiwonder).
  • Исправлена логическая ошибка (Function node with name '...' is not resolved as ordinary function), которая могла возникать при включённой настройке optimize_or_like_chain, если агрегатная или оконная функция находилась в левой части LIKE/ILIKE/match внутри цепочки OR. #110641 (groeneai).
  • Исправлено переполнение знакового целого в toStartOfInterval при экстремально большом количестве интервалов MONTH, WEEK или DAY для значений Date/Date32/DateTime64. #110688 (groeneai).
  • Исправлена ошибка, из-за которой readWKT и readWKTPoint возвращали для POINT EMPTY неинициализированные (в скалярном режиме) или устаревшие координаты предыдущей строки (в векторизованном режиме). Теперь POINT EMPTY отклоняется с ошибкой CANNOT_PARSE_TEXT, поскольку Point в ClickHouse — это фиксированный Tuple(Float64, Float64), не имеющий пустого представления. #110692 (groeneai).
  • Исправлена потеря типа Geometry функцией flipCoordinates: для аргумента типа Geometry результат снова имеет тип Geometry, а не базовый Variant(...), поэтому его можно напрямую передавать в такие функции, как areaCartesian. #110694 (groeneai).
  • Исправлена неканоническая WKB-сериализация пустого полигона: wkb(POLYGON EMPTY) теперь выдаёт numRings = 0 вместо лишнего кольца из нуля точек, поэтому стандартный пустой полигон после обратимого обмена через WKB остаётся неизменным. #110796 (groeneai).
  • При разборе JSON Bool числовые значения 1/0 теперь обрабатываются с учётом настройки allow_special_bool_values. Ранее входные данные JSON, например {"v":1} для Variant(Bool, UInt32), считывались как Bool даже при allow_special_bool_values_inside_variant = 0, поскольку парсеры JSON Bool игнорировали эту настройку, а у Bool приоритет десериализации в Variant выше, чем у целочисленных типов. #110835 (groeneai).
  • Исправлена ошибка, из-за которой throwIf(notLike(col, pattern)) (и другие вызовы throwIf поверх функции) безусловно генерировали исключение, если col имеет тип LowCardinality. Стандартная реализация для LowCardinality выполняла throwIf над всем словарём, а он всегда содержит зарезервированное значение по умолчанию, даже если ни одна строка на него не ссылается. В результате ненулевое значение в этой неиспользуемой ячейке заставляло throwIf генерировать исключение для данных, не удовлетворяющих условию. #110864 (groeneai).
  • Исправлено аварийное завершение при использовании агрегатной функции с комбинатором -Tuple вместе с RESPECT NULLS, если она формировала промежуточное состояние (-State, распределённая агрегация, WITH ROLLUP/WITH CUBE). Комбинированная функция получала имя неверного варианта состояния, из-за чего после сериализации и десериализации её тип AggregateFunction разрешался в несовместимую структуру в памяти. #110930 (groeneai).
  • Исправлена ошибка Nested type LineString cannot be inside Nullable type (ILLEGAL_TYPE_OF_ARGUMENT) при чтении допускающего NULL пространственного столбца MySQL (LINESTRING, POLYGON, MULTILINESTRING, MULTIPOLYGON, MULTIPOINT или обобщённого GEOMETRY) через табличную функцию mysql или движки таблиц/баз данных MySQL. Теперь такие столбцы отображаются в Nullable(String) и содержат значение в том виде, в каком его возвращает MySQL (4-байтовый префикс SRID, за которым следуют данные WKB). POINT по-прежнему отображается в Nullable(Point). #110943 (groeneai).
  • Исправлена сериализация Native для обёрток SimpleAggregateFunction, содержащих версионированные состояния агрегатных функций, при взаимодействии с узлами более старых версий. #110997 (groeneai).
  • Исправлена ошибка CANNOT_CONVERT_TYPE для констант типа Variant (включая Geometry) в распределённых запросах и запросах с параллельными репликами. #111136 (fm4v).
  • Исправлена ошибка LOGICAL_ERROR («Lambda resolved type … is not equal to type from actions DAG …»), возникавшая, если тело лямбда-выражения функции высшего порядка представляло собой if/multiIf с константным условием, где ветвь с литералом Bool сочеталась с ветвью сравнения типа UInt8, например arrayFilter(p -> multiIf(false, true, p = 'ALL'), ['ALL']). #111245 (groeneai).
  • Исправлено переполнение знакового целого в toStartOfInterval с интервалами меньше секунды: для значений DateTime64, отстоящих от нижней границы Int64 не более чем на один интервал, округлённый результат незаметно превращался в бессмысленное положительное значение; теперь функция генерирует исключение DECIMAL_OVERFLOW. #111370 (alexey-milovidov).
  • Исправлено исключение (CANNOT_CONVERT_TYPE или логическая ошибка) в распределённых запросах, использующих комбинатор -Tuple с модификатором RESPECT NULLS / IGNORE NULLS при вложенных комбинаторах, например anyRespectNullsStateTuple(...) IGNORE NULLS. #111570 (alexey-milovidov).
  • Исправлена попытка текстового разбора FixedString, которая при неудачном разборе оставляла в столбце частично добавленные байты. Это могло приводить к логической ошибке Sizes of nested column and null map of Nullable column are not equal при сериализации столбцов Variant/Array/Nullable либо к незаметному смещению байтов результата. #111908 (groeneai).
  • Исправлены исключение и незаметный пропуск данных при чтении динамического подстолбца (пути внутри столбца JSON или Dynamic) через таблицу Buffer. #111948 (alexey-milovidov).
  • Устранена квадратичная сложность в countSubstringsCaseInsensitiveUTF8, из-за которой на строке размером в несколько мегабайт с большим количеством совпадений функция выполнялась несколько минут. Теперь символьное смещение каждого совпадения вычисляется инкрементально, а не пересчитывается с начала строки. #112003 (groeneai).
  • Исправлено переполнение знакового целого в трёхаргументной перегрузке toStartOfInterval: если значение аргумента origin было близко к нижней границе Int64, функция вместо сообщения об ошибке возвращала значение, полученное в результате переполнения. #112045 (alexey-milovidov).
  • Запрещено использование состояний агрегатных функций в параметрах табличных функций, поскольку они там вообще не поддерживаются. #112087 (PedroTadim).
  • Исправлено поведение табличной функции values, которая выводила нелитеральную константу Bool (например, CAST(true, 'Nullable(Bool)')), вставляемую в столбец String или другой текстовый столбец, как 1/0 вместо true/false. #112308 (yakov-olkhovskiy).
  • Исправлена логическая ошибка (приводящая к аварийному завершению в отладочных сборках и сборках с санитайзерами), возникавшая при применении finalizeAggregation к столбцу, в котором состояния агрегатных функций получены от разных функций с общим представлением состояния, но разными типами итогового результата, — например, quantileState и quantilesState(0.9), объединённых через UNION или полученных с помощью arrayReduce. Теперь такие запросы завершаются обычной ошибкой, а не аварийно. #112662 (zainulabidin302).
  • Исправлен разбор целых чисел, не помещающихся в целевой тип, в Poco::NumberParser, который используется для чтения чисел JSON. Такое число не отклонялось, а незаметно разбиралось в неверное значение (например, 18446744073709551617 превращалось в 1), а число UInt64, превышающее максимум Int64, искажалось при преобразовании AST в JSON и обратно. #112904 (alexey-milovidov).
  • Исправлено преобразование константы Bool в правой части IN к типу String левой части в виде '1'/'0' вместо канонических 'true'/'false' (теперь поведение согласовано с CAST и табличной функцией values). #113051 (yakov-olkhovskiy).
  • Исправлено несогласованное форматирование AST для viewIfPermitted: устранены проблемы с функцией, обычно записываемой как оператор (например, not), в ветви ELSE формы табличной функции, а также с ошибочным форматированием формы выражения viewIfPermitted(...) с ELSE. #113652 (alexey-milovidov).
  • Исправлены неопределённое поведение и неверные результаты avg для Date/DateTime/DateTime64/Time/Time64: среднее теперь вычисляется точно в целочисленной арифметике, что устраняет как переполнение на границе Int64 (UB, неверный результат на x86), так и потерю точности Float64 для значений больше 2^53 (заметную при наносекундной точности). #113912 (alexey-milovidov).
  • Исправлена утечка памяти в экспериментальном кодеке сжатия SZ3: если сжатие плохо сжимаемых или повреждённых данных завершалось исключением, временные рабочие буферы не освобождались. #113916 (alexey-milovidov).
  • Исправлена ошибка, из-за которой hasAny, hasAll, has, indexOf, mapContainsKey, mapContainsValue и mapContains возвращали слишком мало строк или завершались ошибкой TOO_LARGE_STRING_SIZE при обращении к индексу bloom_filter с константой типа FixedString. Индекс хешировал константу в дополненном виде, тогда как функция сравнивает её без дополнения, поэтому подходящая гранула пропускалась. #114089 (alexey-milovidov).
  • Исправлена ошибка, из-за которой min и max для столбцов DateTime64 возвращали неверные результаты, если агрегатная функция JIT-компилировалась, а данные содержали временные метки до 1970 года. is_signed не был специализирован для DateTime64 и Time64, производных от Decimal64, поэтому сгенерированный код сравнивал количество тиков как беззнаковые целые числа, и временная метка до 1970 года ошибочно оказывалась максимальной в max и не учитывалась в min. #114168 (groeneai).
  • Исправлена ошибка, из-за которой arrayExists(x -> x = needle, arr) возвращала неверный результат или завершалась ошибкой TOO_LARGE_STRING_SIZE, если элемент массива и искомая подстрока имели разные строковые типы (например, искомая подстрока типа String и элемент Array(FixedString(N))). Оптимизация optimize_rewrite_array_exists_to_has, включённая по умолчанию, заменяла такой вызов на has, которая, в отличие от =, не учитывает дополнение нулями при сравнении. #114496 (groeneai).
  • Исправлено применение текстового индекса для оператора LIKE/ILIKE, используемого с контейнерами Map или JSON. #114544 (ahmadov).
  • Исправлены неопределённое поведение и неверные результаты на граничных значениях в quantile и quantiles для DateTime64 и широких типов Decimal. #114919 (alexey-milovidov).
  • Исправлена ошибка, из-за которой if и multiIf возвращали большое положительное значение вместо отрицательного, если ветвь типа Time сочеталась с Time64, DateTime или DateTime64, а выражение JIT-компилировалось. #115146 (groeneai).
  • Исправлена ошибка, из-за которой timezoneOffset (псевдоним timeZoneOffset) возвращала смещение, ошибочное ровно на сутки, для часовых поясов, чьё смещение от UTC отличается от смещения на 1970-01-01 на целые сутки (например, Pacific/Kiritimati и Pacific/Apia после их перехода через международную линию перемены дат), а также для большинства поясов до 1970 года. Заодно исправлены parseDateTime, parseDateTimeOrNull, parseDateTime64, parseDateTimeInJodaSyntax, EXTRACT(TIMEZONE_HOUR / TIMEZONE_MINUTE ...), %z в formatDateTime, toUTCTimestamp и fromUTCTimestamp, которые используют это смещение. #115332 (groeneai).
  • Исправлена ошибка Code: 349. Cannot convert NULL value to non-Nullable type, возникавшая, когда предикат has или notHas содержит элемент массива со значением NULL, а первичный ключ имеет тип String, Array(String) или Map(String, String). Также исправлены неверные результаты в случае, когда этот элемент имеет тип Dynamic или Variant и содержит NULL. Теперь при анализе ключа значение NULL исключается из множества, как это уже делалось для ключей других типов. #115647 (groeneai).
  • Исправлена ошибка, из-за которой настройка cast_keep_nullable не сохраняла допустимость NULL, если целевой тип — LowCardinality. Приведение значения, которое может быть NULL, к LowCardinality(T) завершалось ошибкой CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN вместо того, чтобы возвращать LowCardinality(Nullable(T)). #115851 (groeneai).

Исправления индексов и кэша запросов

  • Исправлено чтение подстолбцов столбца, у которого задано выражение DEFAULT и который не материализован в части (например, после ALTER TABLE ADD COLUMN или во время ALTER TABLE MATERIALIZE COLUMN): подстолбец заполнялся значениями по умолчанию для типа вместо вычисленного выражения DEFAULT, а транспонированные функции векторного расстояния (cosineDistanceTransposed и другие) для таких столбцов QBit завершались ошибкой SIZES_OF_ARRAYS_DONT_MATCH. #110636 (alexey-milovidov).
  • Исправлено исключение Not-ready Set is passed as the second argument, которое могло возникать, если построение множества для подзапроса IN во время анализа первичного ключа молча завершалось неудачей (например, при тайм-ауте подзапроса с overflow_mode = 'break'), из-за чего множество так и оставалось непостроенным для конвейера запроса. #107924 (alexey-milovidov).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK при выполнении SELECT для таблицы с индексом пропуска данных типа set, если политика строк фильтрует её с помощью всегда истинного условия в сочетании с проверкой неиндексированного столбца. #107971 (tiandiwonder).
  • Функция getClientHTTPHeader теперь корректно считается недетерминированной, поэтому её результат больше не берётся по ошибке из кэша результатов запросов. #108029 (alexey-milovidov).
  • Исправлены неверные результаты, возникавшие, когда кэш условий запросов (use_query_condition_cache = 1) повторно использовал исключение меток, полученное с помощью индексов пропуска данных, для запроса с другим набором применяемых индексов пропуска данных, например при use_skip_indexes = 0, ignore_data_skipping_indices или другом режиме use_skip_indexes_for_disjunctions. Теперь ключом для записей кэша, полученных с помощью индексов пропуска данных, служит фактически применённый набор индексов пропуска данных, а записи кэша условий запросов на уровне строк по-прежнему можно повторно использовать во всех этих случаях. #108548 (groeneai).
  • Исправлено зависание: запрос, читающий данные через кэш файловой системы, мог продолжать ждать завершения текущей загрузки после отмены с помощью KILL QUERY, а удаление refreshable materialized view или выполнение для него SYSTEM STOP VIEW блокировалось, если его обновление застряло в таком ожидании. #109116 (murphy-4o).
  • Исправлены неверные результаты запросов, вызванные некорректным отсечением гранул индексом первичного ключа для таблиц с ключевым столбцом в обратном порядке (DESC), когда у частей нет финальной метки (неадаптивная гранулярность, index_granularity_bytes = 0). #109901 (nihalzp).
  • Исправлены логическая ошибка Expected CommonSubplanReferenceStep to reference CommonSubplanStep, ошибка Subplan cannot be used to build pipeline и логическая ошибка Trying to extract chunk from ChunkBuffer before all inputs are finished для IN (subquery), когда подзапрос содержит коррелированный подзапрос, а множество строится во время анализа индекса. #110491 (alexey-milovidov).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK для транспонированных функций расстояния над столбцами QBit (например, cosineDistanceTransposed), вызываемых со скалярным подзапросом или константным опорным вектором при включённых параллельных репликах. #110729 (alexey-milovidov).
  • Исправлена ситуация, когда текстовый индекс не использовался, если его выражение содержит сравнение с пустой строкой, например arrayFilter(s -> s != '', ...): настройка optimize_empty_string_comparisons переписывает сравнение в notEmpty только на стороне запроса. #112115 (Ergus).
  • Столбцы больше не удаляются, если на них ссылаются одновременно условия фильтрации PREWHERE и WHERE, даже если они переписаны в виртуальный столбец текстового индекса. #114460 (ahmadov).
  • Исправлена логическая ошибка Multi-block postings must be compressed в запросах к таблицам с текстовым индексом в режиме ленивого применения posting-list, возникавшая при отмене запроса во время чтения. #114636 (CurtizJ).
  • Исправлены неверные результаты в случаях, когда предложение WHERE содержало выражение NULL внутри NOT, например SELECT count() FROM t WHERE NOT (id >= 20 AND NULL). Анализ индекса считал такое условие заведомо истинным для всего диапазона, поэтому фильтр пропускался: count() учитывал строки, отбрасываемые запросом, а ALTER TABLE ... DELETE с этим условием удалял строки, которые должны были остаться. #115152 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Join is supported only for pipelines with one output port) для JOIN full_sorting_merge при включённом query_plan_join_shard_by_pk_ranges, когда у одной из сторон после отсечения не остаётся ни одной части — по первичному ключу, по статистике столбцов или из-за того, что таблица пуста. #115352 (alexey-milovidov).
  • Кэш условий запроса отключён для фильтров по _part_starting_offset #115358 (azat).
  • Исправлена ошибка LOGICAL_ERROR: Index with name auto_minmax_index_<column> already exists, возникавшая, когда в одном операторе ALTER TABLE команда RENAME COLUMN сочеталась с другой командой, например MODIFY SETTING, для таблицы с неявными индексами minmax (add_minmax_index_for_numeric_columns и аналогичные настройки). Кроме того, после переименования обычного столбца последующий DROP COLUMN больше не завершается ошибкой UNKNOWN_IDENTIFIER, а последующий ADD COLUMN больше не создаёт столбец без неявного индекса. #116063 (groeneai).
  • Шаблон LIKE/NOT LIKE без подстановочных символов (%, _) теперь использует точный диапазон первичного ключа и поэтому читает столько же гранул, сколько эквивалентный предикат =/!=, а не более широкий префиксный диапазон. #107077 (groeneai).
  • Исправлены ошибка LOGICAL_ERROR (Invalid binary search result in MergeTreeSetIndex) и отсутствие отсечения по индексу в релизных сборках, когда условие IN/NOT IN по первичному ключу оборачивает ключ в intDiv на константу, а ключ является беззнаковым целым числом, значения которого пересекают знаковую границу типа результата intDiv (например, intDiv(uint64_column, -9223372036854775807)). #107586 (groeneai).
  • Исправлена ошибка, из-за которой numericIndexedVectorPointwiseMultiply возвращала пустой результат при умножении на вектор из одних единиц с другой битовой конфигурацией BSI. #108027 (alexey-milovidov).
  • Исправлено переполнение буфера в куче (heap-buffer-overflow) при построении текстового индекса с positions = 1 по большому количеству различных коротких токенов. #108659 (groeneai).
  • Выражения preprocessor и postprocessor текстового индекса теперь могут ссылаться на столбцы ALIAS. #110014 (Ergus).
  • Оптимизация векторного поиска теперь не применяется при использовании LIMIT ... WITH TIES, поскольку она ограничивает ANN-поиск ровно n кандидатами, из-за чего строки с тем же значением, что и у n-й строки, отбрасываются. #110453 (tamish560).
  • Исправлена ошибка, из-за которой текстовый индекс не использовался для ILIKE, если индекс построен по выражению, а не просто по столбцу (например, assumeNotNull(col) с препроцессором lower(...)). Теперь такие запросы используют индекс, а не читают все гранулы. #110595 (ahmadov).
  • Исправлена ошибка LOGICAL_ERROR (LazyMaterializingTransform: Number of rows in lazy chunk N does not match number of offsets M), которая могла возникать в запросах векторного поиска с vector_search_with_rescoring = 1 в сочетании с отложенной материализацией, если несколько расстояний совпадали. #111003 (groeneai).
  • При использовании индекса vector_similarity с квантованием i8 теперь отклоняются векторы, квадрат модуля которых переполняется до бесконечности (ранее такие векторы вызывали неопределённое поведение в usearch и молча порождали мусорные данные). #111085 (groeneai).
  • Исправлено чтение устаревших данных с дисков plain_rewritable при включённом страничном кэше. #111105 (Michicosun).
  • Исправлены неверные результаты count() и потеря строк при фильтрации ключа или minmax-индекса пропуска данных по String (или более узкому FixedString) путём сравнения с более широкой константой FixedString, например toFixedString('abc', 257) = string_col. Отсечение по первичному ключу и minmax строило диапазон по константе, дополненной символами NUL, и ошибочно пропускало подходящие гранулы. #111106 (groeneai).
  • Исправлено чтение файлов Parquet, у которых индекс смещений начинается не со строки 0. Из-за таких файлов нативный ридер Parquet мог возвращать неверные строки или выдавать ошибку LOGICAL_ERROR вместо INCORRECT_DATA. Теперь индекс смещений проверяется при чтении. #114530 (groeneai).

Исправления в области безопасности, доступа, резервного копирования и восстановления

  • RESTORE теперь выполняет fsync для восстановленных файлов частей, если для целевой таблицы включён параметр fsync_after_insert, поэтому восстановленная часть так же устойчива к отключению питания, как и вставленная. Ранее восстановленные файлы лишь записывались и закрывались (fsync не выполнялся), поэтому отключение питания сразу после того, как RESTORE вернул RESTORED, могло оставить части повреждёнными, а таблицу — пустой. #111378 (groeneai).
  • Исправлена уязвимость, из-за которой неаутентифицированный TCP-клиент мог через межсерверный порт проверять существование таблиц и состояние репликации. #99854 (tiandiwonder).
  • Исправлена ошибка, из-за которой для DELETE FROM (легковесное удаление) помимо ALTER DELETE требовалась ещё и привилегия ALTER UPDATE. Пользователь, которому выдана только привилегия ALTER DELETE, теперь может выполнять DELETE FROM, как и указано в документации. #107491 (tiandiwonder).
  • Исправлена ошибка, из-за которой CREATE TABLE ... AS SELECT в базах данных Atomic оставлял пустую таблицу при сбое запроса — например, когда у пользователя нет доступа к таблице, на которую ссылается подзапрос. Ранее при повторной попытке вместо исходной ошибки выдавалось сообщение о том, что таблица уже существует. Теперь таблица создаётся через временную таблицу и становится видимой только после полного заполнения. #108048 (alexey-milovidov).
  • Исправлена ошибка LOGICAL_ERROR (No available columns) при выполнении SELECT count() (или других тривиальных запросов) к таблице, в которой пользователю выдан доступ SELECT только к столбцу ALIAS. #108056 (alexey-milovidov).
  • Исправлена проблема, из-за которой неаутентифицированные запросы могли заставить ClickHouse разрешать имена хостов, переданные в заголовках с перенаправленным адресом клиента. Теперь ClickHouse принимает из этих заголовков только числовые IP-адреса. Недопустимые значения игнорируются при учёте квот по перенаправленному адресу, DNS-разрешение для них не выполняется. Если включён параметр auth_use_forwarded_address, недопустимые перенаправленные адреса отклоняются при аутентификации. Отказы записываются в лог на уровне debug. #111060 (otselnik).
  • Исправлено игнорирование SQL SECURITY DEFINER (и SQL SECURITY NONE) для параметризованных представлений при отключённом анализаторе (enable_analyzer = 0). Ранее выборка из такого представления пользователем без привилегий на базовую таблицу завершалась ошибкой ACCESS_DENIED, хотя при включённом анализаторе то же представление работает. #111458 (groeneai).
  • Исправлен дефект в интеграциях MySQL: переопределение TLS-учётных данных именованной коллекции пустым значением ssl_ca_pem/ssl_cert_pem/ssl_key_pem принималось, если коллекция хранила учётные данные в виде содержимого. В результате настроенный CA или клиентский сертификат незаметно отбрасывался, хотя переопределение должно было отклоняться. #113947 (alexey-milovidov).
  • Исправлена потеря статистики JOIN в EXPLAIN ANALYZE для представления, объявленного с SQL SECURITY DEFINER или SQL SECURITY NONE, тело которого содержит JOIN. В отладочных сборках и сборках с санитайзерами запрос аварийно завершался с логической ошибкой JoinStep analyzed without the analyze mode. #115156 (groeneai).
  • Исправлена ошибка, из-за которой после RESTORE ... AS <new name> список REFRESH ... DEPENDS ON у refreshable materialized view продолжал указывать на исходную базу данных. Восстановленное представление обновлялось в ответ на изменения таблицы, которую оно больше не читало, игнорировало обновления собственного родителя и полностью переставало обновляться после удаления исходной базы данных. #115689 (groeneai).
  • Исправлено исключение LOGICAL_ERROR при создании резервной копии базы данных Replicated, которая параллельно удаляется и создаётся заново; теперь такое резервное копирование корректно завершается ошибкой CANNOT_GET_REPLICATED_DATABASE_SNAPSHOT. #100651 (alexey-milovidov).
  • Запрос GRANT role TO role для одной и той же роли теперь отклоняется с ошибкой BAD_ARGUMENTS, а не создаёт без предупреждения запись в system.role_grants, ссылающуюся на саму себя. #103315 (zxuhan).
  • BACKUP базы данных MaterializedPostgreSQL больше не зависает навсегда с сообщением «Table … were created or changed its definition during scanning» и теперь действительно сохраняет данные таблиц (делегируя это базовому движку ReplacingMergeTree); их можно восстановить как автономную таблицу ReplacingMergeTree. #107433 (alexey-milovidov).
  • Запрос EXISTS <dictionary> теперь разрешён пользователю, у которого есть только привилегия SHOW DICTIONARIES на словарь (ранее требовалась SHOW TABLES). #108084 (alexey-milovidov).
  • Исправлена очистка после BACKUP ... TO Memory(...), завершившегося ошибкой до финализации: неудавшаяся резервная копия оставалась зарегистрированной, и её имя нельзя было использовать повторно. #109947 (jkartseva).
  • Исправлена логическая ошибка ReadBuffer is canceled. Can't read from it. (аварийное завершение сервера в сборках debug/sanitizer), которая могла возникать при чтении zip-архива (например, при RESTORE из резервной копии в формате zip), если предыдущее чтение из того же архива прервалось с ошибкой на середине потока. #110197 (groeneai).
  • Исправлено повреждение кучи, которое могло приводить к аварийному завершению сервера при остановке: const-метод AccessRights::getFilters изменял дерево прав доступа, совместно используемое параллельными запросами. #112692 (groeneai).

Распределённое выполнение, таблицы, представления и словари

  • Исправлена ложная ошибка Inconsistent AST formatting для ALTER TABLE ... MOVE PART ... TO SHARD '<path>'. Форматировщик запросов терял ключевое слово SHARD, из-за чего переформатированный запрос не удавалось разобрать обратно и возникала ошибка LOGICAL_ERROR (обрабатываемое исключение в релизных сборках, аварийное завершение в отладочных сборках и сборках с санитайзерами). #109060 (groeneai).
  • Исправлена логическая ошибка (!part.empty()), возникавшая, когда таблица Distributed, определённая с пустым именем удалённой базы данных, использовалась в JOIN при distributed_product_mode = 'local'. #110677 (groeneai).
  • Исправлена ошибка, из-за которой запрос с DISTINCT и упорядоченным LIMIT/OFFSET возвращал неверные строки, если подсказка раннего останова DISTINCT не могла ограничить начало результата: при отрицательном LIMIT (возвращалось начало вместо конца), при дробном LIMIT/OFFSET (дробь вычисляется только после полного чтения) и при одиночном OFFSET без LIMIT (конец после смещения отбрасывался). Например, SELECT DISTINCT intDiv(x, 100) FROM t ORDER BY intDiv(x, 100) LIMIT -1 для таблицы из нескольких частей возвращал наименьшее уникальное значение вместо наибольшего. #111326 (groeneai).
  • Исправлена ошибка, из-за которой парсер не принимал псевдоним после подзапроса в DESCRIBE TABLE и выдавал синтаксическую ошибку. Исправляет https://github.com/ClickHouse/ClickHouse/issues/100031. #100205 (yariks5s).
  • Исправлено аварийное завершение сервера (Logical error: 'Block structure mismatch'), которое могло происходить при конкурентном INSERT во время выполнения ALTER RENAME COLUMN в базе данных Atomic с lazy_load_tables = 1 после DETACH DATABASE / ATTACH DATABASE. #104852 (groeneai).
  • Исправлены повреждение имён столбцов и исключение BAD_ARGUMENTS, вызванные настройкой inject_random_order_for_select_without_order_by. При включённой настройке SELECT-запросы с несколькими столбцами больше не завершаются ошибкой, а имена выходных столбцов (например, для CREATE TABLE AS SELECT, CREATE VIEW AS SELECT, JSONEachRow) сохраняются и не заменяются внутренними псевдонимами __subquery_column_<UUID>. #105896 (groeneai).
  • Исправлена вводящая в заблуждение подсказка «Maybe you meant X?» после перезапуска сервера (или DETACH/ATTACH DATABASE): при удалении уже удалённой таблицы в качестве альтернативы предлагалось только что удалённое имя. Теперь при отключении задачи асинхронной загрузки удаляются из DatabaseOrdinary::startup_table и load_table. #106238 (groeneai).
  • Исправлены движки таблиц и баз данных MaterializedPostgreSQL: теперь отдельную таблицу или базу данных можно реплицировать из нестандартной схемы PostgreSQL (materialized_postgresql_schema), в том числе когда таблицы с одинаковым именем существуют в нескольких схемах одной базы данных (ранее они использовали общие публикацию и слот репликации и мешали друг другу). #107425 (alexey-milovidov).
  • Исправлены ошибки: NO_SUCH_COLUMN_IN_TABLE, когда запрос с параллельными репликами выбирает столбец ALIAS таблицы, передаваемой как временная таблица GLOBAL JOIN; MULTIPLE_EXPRESSIONS_FOR_ALIAS, когда в обеих частях распределённого JOIN объявлен столбец ALIAS с одинаковым именем; UNKNOWN_IDENTIFIER, когда в таблице Distributed объявлен столбец ALIAS, основанный на другом столбце ALIAS, в том числе используемый в качестве ключа JOIN USING. #107700 (yakov-olkhovskiy).
  • Исправлено знаковое целочисленное переполнение, возникавшее, когда refreshable materialized view повторяет неудачное обновление при очень большом значении refresh_retries (близком к максимуму Int64). В сборках с санитайзером неопределённого поведения это переполнение могло приводить к аварийному завершению сервера. #108005 (groeneai).
  • Исправлено исключение (CANNOT_PARSE_TEXT) при загрузке словаря с составным ключом, столбцы ключа которого не являются первыми столбцами в определении словаря, если используется локальный источник ClickHouse с явно заданным запросом. Теперь столбцы источника сопоставляются со структурой словаря по имени, а не по позиции. #108053 (alexey-milovidov).
  • Исправлен сбой (разыменование нулевого указателя) при запросе к таблице Hive без предложения WHERE, например SELECT * FROM hive_table. #108094 (alexey-milovidov).
  • Исправлен сбой сервера (ошибка сегментации), который мог возникать, когда распределённый запрос ссылался на ещё не материализованный CTE MATERIALIZED как на внешнюю таблицу, а удалённый источник создавался отложенно (delayed source). Причиной сбоя было разыменование нулевого указателя на Logger внутри RemoteQueryExecutor::sendExternalTables(). #108547 (groeneai).
  • Исправлена логическая ошибка (Equal values are not contiguous within the range assumed to be sorted) при выполнении DISTINCT поверх чтения STREAM (SELECT DISTINCT ... FROM table STREAM). Оптимизации чтения в порядке сортировки больше не применяются к чтению STREAM, поскольку оно возвращает строки в порядке фиксации, а не в порядке ключа сортировки. #108568 (groeneai).
  • Исправлено исключение (Cannot find sharding key column, а в debug-сборках и сборках с санитайзером — аварийное завершение сервера), возникавшее, когда ключ сегментирования таблицы Distributed представляет собой выражение, которое анализатор сворачивает в константу, например if(1, toInt32(id), toInt32(id) + 1), при optimize_skip_unused_shards = 1. #108737 (groeneai).
  • Исправлено аварийное завершение сервера (LOGICAL_ERROR / срабатывание assertion в debug-сборках и сборках с санитайзером) при отмене INSERT ... SELECT через таблицу Alias без исключения, например при timeout_overflow_mode = 'break'. #108783 (groeneai).
  • Исправлено аварийное завершение сервера (LOGICAL_ERROR / срабатывание assertion в debug-сборках и сборках с санитайзером) при отмене INSERT ... SELECT в таблицу TimeSeries без исключения, например при timeout_overflow_mode = 'break'. #108796 (tiandiwonder).
  • Исправлены периодические сбои распределённых запросов с ошибкой UNEXPECTED_PACKET_FROM_SERVER («expected TablesStatusResponse, got ProfileInfo»), возникавшие при повторном использовании из пула соединения, которое предыдущий отменённый запрос оставил в рассинхронизированном состоянии. #108854 (alexey-milovidov).
  • Исправлена ошибка LOGICAL_ERROR (CTE '...' does not have query tree, but was not planned yet), возникавшая, когда на CTE MATERIALIZED ссылались из нескольких позиций дерева JOIN (например, из двух соединяемых подзапросов или из соединяемого подзапроса и скалярного подзапроса в WHERE) в запросе к таблице Distributed. Теперь запрос выполняется успешно, а не завершается исключением (в debug-сборках и сборках с санитайзером это приводило к аварийному завершению сервера). #108924 (groeneai).
  • Исправлена проблема безопасности памяти, из-за которой асинхронные задачи, запланированные при обработке materialized view, могли продолжать использовать учёт ресурсов на уровне запроса уже после его завершения. #108988 (filimonov).
  • Исправлена ошибка LOGICAL_ERROR (“Cannot find __grouping_set column in header of MergingAggregatedTransform with grouping sets” или “Chunk info was not set for chunk in MergingAggregatedTransform”), которая могла возникать без анализатора в запросах с UNION ALL/INTERSECT/EXCEPT, если одна ветвь использует GROUP BY GROUPING SETS с параллельными репликами, а другая — FINAL. #109003 (groeneai).
  • Исправлен сбой CREATE TABLE ... AS SELECT FROM s3Cluster(...) (и других кластерных табличных функций, таких как fileCluster/urlCluster) с ошибкой NOT_FOUND_COLUMN_IN_BLOCK в базе данных Replicated. #109266 (groeneai).
  • Исправлена ошибка (NOT_FOUND_COLUMN_IN_BLOCK или std::bad_function_call в более ранних версиях) при выполнении CREATE TABLE ... ON CLUSTER ... AS SELECT с чтением из таблицы Distributed в кластере с двумя и более шардами. #109407 (alexey-milovidov).
  • Исправлена малопонятная внутренняя ошибка (Method getResultType is not supported for TABLE query tree node), возникавшая при использовании табличного выражения в качестве левого аргумента оператора IN; теперь для таких запросов выводится понятное сообщение об ошибке. #109412 (alexey-milovidov).
  • Исправлена логическая ошибка Bad cast from type DB::FunctionNode to DB::ConstantNode (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами) при выполнении SELECT ... ORDER BY ... WITH FILL к таблице Distributed с низким значением optimize_const_name_size. #109938 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (Left and right columns have same names) в оптимизаторе порядка JOIN, которая могла возникать при JOIN через запятую над многотабличным представлением, если включена настройка query_plan_merge_expression_into_join. #110227 (groeneai).
  • Исправлена редкая ошибка Logical error: 'No more packets are available.', возникавшая при выполнении корректного распределённого запроса с LIMIT и приводившая к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами. #110334 (groeneai).
  • Исправлена ошибка парсера, из-за которой COMMENT ошибочно воспринимался как неявный псевдоним, если запрос SELECT заканчивался сразу после идентификатора таблицы (например, ... FROM t COMMENT 'x'): вместо применения комментария к представлению/таблице возникала вводящая в заблуждение синтаксическая ошибка. #110372 (adityaksolves).
  • Исправлен неверный результат: length() (и размерность QBit) для столбца FixedString возвращала 0 вместо фиксированного размера N при использовании параллельных реплик, если в запросе был селективный фильтр. #110427 (groeneai).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK для запросов с подзапросом во FROM при работе параллельных реплик в режиме custom_key_sampling / custom_key_range. Ранее такие запросы (например, SELECT * FROM (SELECT id, k, v FROM t WHERE id < 20) ORDER BY k) завершались ошибкой Not found column __table2.id in block .... #110690 (groeneai).
  • Исправлена ошибка Logical error: 'clock' (в отладочных сборках и сборках с санитайзерами сервер аварийно завершается, а в релизных сборках происходит бесконечное зависание) при выполнении EXPLAIN ANALYZE для запроса с потоковым чтением (FROM ... STREAM), которое не является простым табличным выражением верхнего уровня, а вложено в подзапрос (например, внутри WHERE ... IN (...) или CTE) либо скрыто за обычным или параметризованным представлением. Теперь EXPLAIN ANALYZE отклоняет такие запросы с ошибкой NOT_IMPLEMENTED — так же, как уже отклоняет потоковое чтение верхнего уровня. #110935 (groeneai).
  • Исправлено разрешение полностью квалифицированных имён столбцов, таких как db.table.column, в анализаторе для таблиц, имя которых совпадает с именем их базы данных. #110976 (alexey-milovidov).
  • Исправлены ошибки NOT_FOUND_COLUMN_IN_BLOCK / THERE_IS_NO_COLUMN (а в некоторых релизах — неверные результаты без каких-либо ошибок) для RIGHT JOIN, когда задан параметр parallel_replicas_min_number_of_rows_per_replica и в проекцию попадает столбец левой таблицы. #111332 (groeneai).
  • Исправлено состояние гонки в исполняемых UDF, движке таблицы executable и исполняемых словарях, при котором вызов fcntl для уже закрытого файлового дескриптора мог повредить посторонний дескриптор параллельного запроса (сбросив флаг O_NONBLOCK), из-за чего запросы могли зависать на неопределённое время. #111779 (Algunenano).
  • Исправлена ошибка LOGICAL_ERROR («Invalid number of rows in Chunk»), а в усиленных сборках — связанное с ней аварийное завершение из-за выхода за границы, для ORDER BY ... WITH FILL ... INTERPOLATE над таблицей Distributed с двумя или более сегментами, над clusterAllReplicas или над параллельными репликами с пользовательским ключом, в том числе при пустых результатах. Теперь WITH FILL применяется только на узле, формирующем итоговый результат, что также устраняет дублирование сгенерированных строк заполнения между сегментами/репликами. #111919 (yakov-olkhovskiy).
  • Исправлено бесконечное зависание DROP TABLE ... SYNC, если запрос к system.replicas был прерван до того, как были обработаны его запросы статуса. #112164 (evillique).
  • Исправлено исключение LOGICAL_ERROR (Block structure mismatch in joined block stream) при JOIN нескольких таблиц, когда оба вложенных JOIN не возвращают выходных столбцов, например SELECT count() FROM t1, t2, t3, t4 WHERE (t1.b = t2.b) AND (t3.a = t4.a) при значении query_plan_optimize_join_order_limit, равном 0 или 1. #112205 (groeneai).
  • Исправлена логическая ошибка Cannot add step Expression to QueryPlan because it has incompatible header with root step JoinLazyColumnsStep для запроса с FINAL, фильтром PREWHERE, небольшим LIMIT и make_distributed_plan = 1, когда выбираемые столбцы перечислены в порядке, отличном от порядка столбцов таблицы. Механизм отложенной материализации заменял узел плана, не сохраняя его выходной заголовок, из-за чего план запроса становился несогласованным. #112303 (groeneai).
  • Исправлены неверные результаты и логическая ошибка, возникавшие при использовании старого анализатора, когда аргумент, который должен быть константой (например, масштаб в toDecimal32 или часовой пояс в toDateTime), берётся из скалярного подзапроса. Такой аргумент анализировался так, будто его значение равно нулю или пусто, поэтому объявленный тип результата не совпадал с вычисленным значением, а CREATE VIEW и CREATE MATERIALIZED VIEW сохраняли неверный тип столбца. #112492 (groeneai).
  • Исправлены логическая ошибка и неверная запись зависимости, возникавшие, когда тело обычного VIEW ссылается на таблицу или словарь через параметр запроса, например CREATE VIEW v AS SELECT x FROM {db:Identifier}.t. Такое представление больше не регистрирует ссылочную зависимость от одноимённой таблицы текущей базы данных, поэтому не связанные с ним таблицы снова можно удалять. #112704 (groeneai).
  • Исправлена логическая ошибка, возникавшая при использовании движка таблицы Join в правой части JOIN, секция ON которого содержит условие, ссылающееся на столбцы обеих таблиц, например ON (t.key = j.key) AND (t.a < j.a). Теперь такой запрос отклоняется с понятным исключением, а не завершается ошибкой required columns: ... but not found any in left table или std::bad_variant_access. #112815 (groeneai).
  • Исправлены неопределённое поведение и незаметная ошибка планирования при постановке фоновой задачи с очень большой задержкой — например, в refreshable materialized view с огромным периодом REFRESH AFTER. Теперь задержка ограничивается максимальным представимым значением и не переполняется. #113041 (groeneai).
  • Исправлено сообщение об ошибке, возникавшей, когда асинхронному INSERT в таблицу Distributed требуется каталог очереди, имя которого превышает ограничение файловой системы в 255 байт (что возможно при use_compact_format_in_distributed_parts_names = 0). Для шарда с internal_replication это была ошибка LOGICAL_ERROR, а в остальных случаях — Code: 1001. std::exception без указания источника; теперь в обоих случаях выдаётся ARGUMENT_OUT_OF_BOUND с указанием таблицы, кластера и ограничения. #113083 (groeneai).
  • UNDROP TABLE теперь можно прервать с помощью KILL QUERY, пока он ожидает, когда выполняющиеся запросы освободят удалённую таблицу. #113263 (alexey-milovidov).
  • Исправлены бесконечное зависание DROP TABLE и утечка памяти после сбоя запроса, использующего материализованное CTE. Таблица оставалась в очереди удаления вплоть до перезапуска сервера. #113397 (tiandiwonder).
  • Исправлены segfault и ошибка LOGICAL_ERROR (No host found for exchange stream final_result__0_0), возникавшие, когда подзапрос задаёт distributed_plan_execute_locally в собственной секции SETTINGS при включённом make_distributed_plan. Распределённый план и выполняющий его код считывали настройку из разных контекстов и могли получать разные значения, из-за чего инициатор строил внутренне противоречивый конвейер. #113422 (groeneai).
  • Исправлена проблема, из-за которой запрос CREATE TABLE ... AS SELECT с завершившимся ошибкой заполняющим SELECT невозможно было прервать при включённой настройке database_atomic_wait_for_drop_and_detach_synchronously: внутренний DROP временной таблицы для очистки ожидал фоновую очередь удаления и игнорировал как KILL QUERY, так и max_execution_time. #113504 (groeneai).
  • Исправлены неверные результаты, а в сборке с включёнными assertion — аварийное срабатывание assertion для JOIN со словарём, секция ON которого содержит условие неравенства по обеим таблицам, например ON (t.key = d.key) AND (t.a * 10 < d.a), при включённой настройке join_use_nulls. Условие вычислялось по столбцу, прочитанному с несоответствующим типом, поэтому строки могли сопоставляться произвольно. #113534 (alexey-milovidov).
  • Исправлена ошибка, из-за которой параметризованное представление теряло свою базу данных, когда запрос, ссылающийся на него без указания базы данных, отправлялся на сегмент: в результате сегмент искал имя в собственной базе данных по умолчанию. В зависимости от содержимого этой базы данных запрос либо завершался ошибкой UNKNOWN_FUNCTION, либо молча возвращал строки из другого представления. Проблема затрагивала IN, JOIN и remote() через таблицу Distributed. #113550 (groeneai).
  • Исправлена ошибка Unsupported JOIN keys of type keys256 in StorageJoin при чтении таблицы на движке Join с составным ключом (из нескольких столбцов) или ключом из одного 16/32-байтового значения, например UUID, Int256 или FixedString(4). Такую таблицу можно было создать, записать в неё данные и выполнять с ней JOIN, но прочитать её с помощью SELECT было невозможно. #113578 (groeneai).
  • Исправлена логическая ошибка Sending a distributed query with unknown (zero) client version, возникавшая при подключении таблицы Distributed без описания структуры поверх удалённого сегмента или при её загрузке из метаданных, записанных сервером более старой версии. #113675 (alexey-milovidov).
  • Исправлена ошибка LOGICAL_ERROR, возникавшая, когда в SELECT модификатор STREAM применялся к именованной таблице одновременно с параллельными репликами в режиме задач чтения. Если materialized CTE использовалось как множество IN в PREWHERE, сервер выдавал ошибку Reading from materialized CTE ... DelayedPortsProcessor gate is missing in the query plan (а в отладочных сборках и сборках с санитайзерами аварийно завершался). Теперь таблица с STREAM отклоняется при запросе параллельных реплик: при enable_parallel_replicas = 2 запрос завершается ошибкой SUPPORT_IS_DISABLED, а при 1 выполняется без них — точно так же, как это уже происходит для FINAL. #113754 (groeneai).
  • Устранена квадратичная сложность разбора аргумента адреса в табличных функциях remote, mysql и аналогичных: очень длинный адрес (например, дополненный нулями FixedString размером в мегабайт) приводил к зависанию запроса на этапе анализа, где его невозможно было отменить. #113918 (alexey-milovidov).
  • Исправлена ложная ошибка Failed to drop temporary table after refresh. Table ... is left behind and requires manual cleanup., которая записывалась в лог при отмене обновления refreshable materialized view (например, из-за остановки сервера) при включённой настройке database_atomic_wait_for_drop_and_detach_synchronously. На самом деле временная таблица удалялась, так что ручная очистка не требовалась. #113957 (groeneai).
  • Исправлено отсутствие строки в system.query_views_log для materialized view, завершающегося ошибкой во время сбора его зависимостей при включённой настройке materialized_views_ignore_errors. В отладочных сборках и сборках с санитайзерами это также приводило к аварийному завершению сервера с std::out_of_range вместо записи представления в лог. #114064 (groeneai).
  • Исправлены несогласованные результаты, возникавшие, когда фильтр по неключевому столбцу правой таблицы проталкивался ниже ANY INNER JOIN. #114313 (kirillshokhin).
  • Исправлены утечка внутренней таблицы _tmp_replace_* при выполнении CREATE OR REPLACE и ошибка NOT_IMPLEMENTED при выполнении CREATE OR REPLACE VIEW, возникавшие при заданной настройке ignore_drop_queries_probability. Внутренние операции DROP являются шагами одной пользовательской инструкции, поэтому внедрение сбоев DROP к ним больше не применяется. #114420 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR при чтении таблицы Delta Lake, у которой в metaData.partitionColumns указан столбец, не объявленный в metaData.schemaString. Теперь такие метаданные отклоняются с ошибкой BAD_ARGUMENTS в считывателе delta-kernel и INCORRECT_DATA в устаревшем считывателе при любом чтении таблицы или её схемы из снимка, а не только когда запрос содержит предикат. #114538 (groeneai).
  • Исправлена ошибка, из-за которой статистика хеш-таблиц, а вместе с ней и предварительное выделение памяти под хеш-таблицы агрегации, незаметно и навсегда отключалась для всего сервера, если первой агрегацией после запуска сервера оказывался запрос с отложенной оптимизацией FINAL (query_plan_optimize_lazy_final). #114597 (alexey-milovidov).
  • Исправлена утечка вытесненной при ротации целевой таблицы refreshable materialized view при включённом параметре ignore_drop_queries_probability. Запрос DROP, который выполняется при обновлении для удаления предыдущей целевой таблицы, является шагом обновления, а не запрошенным пользователем DROP, поэтому внедрение сбоев к нему больше не применяется. #114622 (groeneai).
  • Исправлена ошибка, из-за которой ANY RIGHT JOIN и SEMI RIGHT JOIN с несколькими условиями, объединёнными через OR, в секции ON возвращали некоторые строки правой таблицы дважды и теряли совпадения для других. Проблема затрагивала и явно указанный ANY LEFT JOIN, поскольку планировщик может поменять таблицы местами и выполнить его как ANY RIGHT JOIN. #114676 (vdimir).
  • Исправлена ошибка LOGICAL_ERROR (Cannot find input column ... on its position in inputs of expression actions DAG), возникавшая, если в запросе есть JOIN над таблицей, столбец с текстовым индексом которой используется в предикатах полнотекстового поиска одновременно в PREWHERE и WHERE. #114771 (groeneai).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK при каждом INSERT в таблицу, в которой объявлено STATISTICS(...) для столбца ALIAS или EPHEMERAL, из-за чего такие таблицы фактически становились доступны только для чтения. #115231 (groeneai).
  • Исправлена работа dictGet и его вариантов в распределённых запросах: неполное имя словаря теперь привязывается к текущей базе данных инициатора, а не разрешается относительно текущей базы данных каждого шарда, где словарь либо не находился, либо разрешался в другой словарь с тем же именем. #115541 (alexey-milovidov).
  • Исправлена ошибка, из-за которой при восстановлении базы данных или таблицы под новым именем из тел сохранённых представлений удалялись псевдонимы таблиц, и чтение восстановленного представления завершалось ошибкой UNKNOWN_IDENTIFIER. #115645 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR «Reading from materialized CTE ‘X’ before its materialization completed - DelayedPortsProcessor gate is missing in the query plan», возникавшая при чтении CTE с MATERIALIZED внутри подзапроса IN над таблицей Distributed. #115740 (groeneai).
  • Исправлена ошибка BAD_ARGUMENTS «Dictionary not found» при вызове dictGet после команды DETACH DICTIONARY … PERMANENTLY, отклонённой проверкой зависимостей (HAVE_DEPENDENT_OBJECTS). Теперь, если отсоединение отклонено, словарь остаётся полностью работоспособным. #105259 (groeneai).
  • Исправлена ошибка Logical error: 'removed' (аварийное завершение сервера в отладочных сборках) в фоновой очереди удаления таблиц. Она могла возникать при повторном использовании одного и того же явно заданного UUID в нескольких запросах CREATE OR REPLACE TABLE, из-за чего в очередь попадало несколько удалённых таблиц с одним и тем же UUID. #107031 (groeneai).
  • Исправлена остановка репликации всей базы данных в MaterializedPostgreSQL (с ошибкой LOGICAL_ERROR: Columns number mismatch), если структура одной реплицируемой таблицы изменилась, пока сервер был остановлен. Теперь пропускается только затронутая таблица, и её можно восстановить с помощью DETACH/ATTACH. #107427 (alexey-milovidov).
  • Исправлен сильный перекос в распределении работы при использовании параллельных реплик, когда в кластере есть неактивные реплики (например, устаревшие записи, оставшиеся после автомасштабирования). Координатор чтения больше не учитывает такие реплики, поэтому работа распределяется между доступными репликами, а не скапливается на одной из них. #107805 (alexey-milovidov).
  • Исправлено зависание SYSTEM RELOAD DICTIONARIES (и RELOAD DICTIONARY), когда множество словарей MySQL, определённых в XML, использовали общий пул соединений через share_connection. Теперь такие пулы учитывают параметры connection_pool_size и connection_wait_timeout (по умолчанию 5 секунд) из конфигурации — так же, как словари, определённые через именованные коллекции. #108083 (alexey-milovidov).
  • Исчерпание повторных попыток для реплицируемых распределённых DDL-запросов, выполняемых лидером, больше не блокирует навсегда последующие DDL-запросы с ON CLUSTER. #108505 (ahaanlimaye).
  • Исправлено возможное аварийное завершение (use-after-free) при одновременном выполнении SYSTEM FLUSH DISTRIBUTED и DROP TABLE для одной и той же таблицы Distributed. #108684 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (local_replica_plan_reading_step->getAnalyzedResult() == nullptr) в планировщике автоматических параллельных реплик, которая могла возникать при включённом automatic_parallel_replicas_mode и значении parallel_replicas_min_number_of_rows_per_replica больше 0. #109011 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (creation_csn is not set while removal_csn is set to 1), которая могла возникать, когда нетранзакционный TRUNCATE выполнялся одновременно с незакоммиченной транзакцией, вставлявшей данные в ту же таблицу. Теперь такой TRUNCATE не удаляет части, созданные ещё не закоммиченными транзакциями. #109598 (tuanpach).
  • Движки внешних баз данных (например, PostgreSQL) больше не передают во внешнюю СУБД сравнения диапазонов (>=, >, <=, <) для столбцов типа UUID. ClickHouse и внешние СУБД упорядочивают UUID по-разному, поэтому передача таких условий незаметно приводила к потере строк в результате; теперь эти предикаты вычисляет сам ClickHouse. #109833 (vismaytiwari).
  • Исправлено аварийное завершение сервера в движке баз данных MaterializedPostgreSQL, которое могло происходить, если таблицу отсоединяли (или меняли её структуру), пока она ещё находилась в очереди на синхронизацию. #110596 (alexey-milovidov).
  • Исправлена перезапись типа столбца EPHEMERAL серверными правилами query_masking_rules. Если правило срабатывало внутри типа, CREATE TABLE сохранял неверный тип или завершался ошибкой. #112048 (alexey-milovidov).
  • Исправлен выход за нижнюю границу диапазона беззнакового целого при проверке длины имени таблицы, из-за которого можно было создать таблицу, которую затем невозможно удалить. Когда экранированное имя базы данных достигало 214 байт, лимит, вычисляемый для имени файла metadata_dropped, переполнялся, поэтому CREATE TABLE выполнялся успешно, а последующий DROP TABLE или DROP DATABASE завершался ошибкой File name too long. Теперь такое имя отклоняется с ошибкой ARGUMENT_OUT_OF_BOUND — той же, что уже возвращалась для значений чуть ниже этой границы. #112527 (groeneai).
  • Исправлена ошибка, из-за которой RENAME TABLE проверял максимальную длину имени таблицы для исходной базы данных, а не для целевой. При переносе таблицы в базу данных с длинным именем могла появиться таблица, которую нельзя было удалить с помощью DROP TABLE, а перенос таблицы из такой базы данных, наоборот, ошибочно отклонялся. #113019 (groeneai).
  • Исправлен столбец views в query_log при вставке в таблицу Alias, целевая таблица которой запускает materialized view: ранее он всегда оставался пустым. #113076 (eclbg).
  • Некорректные выражения parallel_replicas_custom_key, например tuple() или (x, y), теперь отклоняются с ошибкой ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER, а не приводят к чтению за пределами списка типов пользовательского ключа. #113359 (nickitat).
  • Исправлена ошибка, из-за которой RENAME DATABASE допускал настолько длинное целевое имя, что таблицы базы данных становилось невозможно удалить. Проверка длины имени таблицы теперь выполняется независимо от check_table_dependencies и распространяется также на отсоединённые таблицы, которые раньше вообще не проверялись и поэтому были подвержены проблеме даже при настройках по умолчанию. #113557 (groeneai).
  • При фоновых вставках в таблицы с движком Distributed задержки, вызванные повторяющимися ошибками отправки данных на удалённые шарды, теперь сокращаются после устранения ошибок. Раньше задержка только росла и никогда не сбрасывалась. #87378 (Blackmorse).
  • Теперь отклоняются рукопожатия по собственному протоколу, использующие USER_INTERSERVER_MARKER для неизвестного кластера или для кластера, настроенного без <secret>. Раньше такое рукопожатие позволяло неаутентифицированному клиенту перейти в режим межсерверного взаимодействия и отправлять пакеты протокола, доступные до аутентификации (например, TablesStatusRequest), которые обрабатывались с использованием fake_interserver_context. Так клиент мог получать сведения о локальных таблицах, не подтверждая знание секрета кластера. #99675 (MillaFleurs).

Исправления в SQL, анализаторе и JOIN

  • Исправлена подстановка параметров запроса внутри определений именованного предложения WINDOW. Ранее параметры в нём молча оставались без подстановки, а незаданный параметр Identifier мог приводить к исключению Logical error: '!part.empty()' при выполнении EXPLAIN SYNTAX. #110506 (alexey-milovidov).
  • Исправлено редкое аварийное завершение сервера при одновременном удалении или замене refreshable materialized view. В RefreshTask::doScheduling происходило разыменование нулевого указателя, если другой поток устанавливал view задачи в nullptr, пока код планирования временно освобождал свой мьютекс. #105588 (groeneai).
  • Исправлен неверный результат после DETACH/ATTACH или перезапуска сервера для представления, определённого с EXCEPT или INTERSECT, операндом которого является цепочка UNION. Форматировщик не добавлял скобки вокруг дочерних UNION у INTERSECT/EXCEPT, поэтому при повторном разборе сохранённого SQL приоритет операций оказывался обратным. #105935 (groeneai).
  • Исправлены неверные результаты (дублирующиеся строки) для SELECT DISTINCT поверх GROUP BY с WITH CUBE, WITH ROLLUP или GROUPING SETS по тем же ключам. Оптимизация query_plan_remove_redundant_distinct больше не удаляет DISTINCT в этих случаях, поскольку модификаторы группировки выдают дополнительные строки, в которых столбцы ключа заполнены значениями по умолчанию, и они могут совпасть с реальными значениями групп. #107072 (groeneai).
  • Исправлен неверный результат OUTER JOIN, когда фильтр в предложении WHERE является конъюнкцией с постоянным членом (например, p AND 1 или WHERE p QUALIFY NULL, где QUALIFY NULL объединяется с WHERE). Постоянный конъюнкт мог проталкиваться в несохраняемую сторону JOIN и удаляться из фильтра после JOIN, из-за чего JOIN выдавал несопоставленные строки, в которых столбцы этой стороны были заполнены значениями по умолчанию, и такие строки ошибочно проходили фильтр. #107084 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (“Cannot find input column … on its position in inputs of expression actions DAG”), приводившая к аварийному завершению сервера для коррелированного скалярного подзапроса над источником, который дважды проецирует один и тот же идентификатор столбца (например, SELECT number, *), при correlated_subqueries_default_join_kind = 'left'. #107112 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами), возникавшая при старом анализаторе (enable_analyzer = 0), когда JOIN использует null-безопасный оператор сравнения (<=> / IS NOT DISTINCT FROM), а один из ключей является скалярным подзапросом, например ... JOIN t2 ON (SELECT x FROM t1) <=> t2.k. Теперь такой запрос возвращает обычную ошибку NOT_FOUND_COLUMN_IN_BLOCK вместо логической ошибки. #108123 (groeneai).
  • Исправлены исключения LOGICAL_ERROR (Join is supported only for pipelines with one output port) и NOT_IMPLEMENTED (MergeJoinAlgorithm is not implemented for strictness Semi) при использовании join_algorithm = 'full_sorting_merge' для SEMI/ANTI JOIN, включая JOIN, полученные в результате декорреляции коррелированного подзапроса EXISTS. Теперь full_sorting_merge отклоняет сочетания строгости и вида JOIN, которые не может выполнить, поэтому планировщик переключается на другой включённый алгоритм или сообщает, что JOIN выполнить невозможно. #108658 (groeneai).
  • Исправлена ошибка, из-за которой строка WITH TOTALS в JOIN могла содержать значения по умолчанию (например, 0) вместо константных значений, получаемых из константного подзапроса на одной из сторон JOIN. Неверный результат возникал только при некоторых порядках соединения таблиц или при использовании настройки query_plan_join_swap_table. #108807 (vdimir).
  • Исправлено аварийное завершение при запуске (Cannot allocate ThreadStack, EINVAL) в сборках с glibc на процессорах с большим размером стека сигналов (например, Intel Sapphire Rapids / Granite Rapids с ядром, поддерживающим AMX): размер альтернативного стека сигналов не округлялся вверх до значения, кратного размеру страницы, перед вызовом aligned_alloc. #108813 (groeneai).
  • Исправлена логическая ошибка Block structure mismatch in JoinStep (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами), возникавшая, когда коррелированный подзапрос декоррелируется в JOIN, а исходное отношение содержит одно и то же имя столбца несколько раз, например WITH t AS (SELECT number, * FROM numbers(3)) SELECT *, (SELECT t.number WHERE t.number >= 0) FROM t при correlated_subqueries_default_join_kind = 'right'. #109114 (groeneai).
  • Исправлено поведение CREATE USER ... HOST LIKE 'a', 'b' (и аналогичного ALTER USER), при котором без каких-либо предупреждений сохранялся только первый шаблон. Теперь все указанные шаблоны HOST LIKE сохраняются в списке разрешённых хостов пользователя. #109187 (groeneai).
  • Исправлен неожиданный результат ANY JOIN с константным условием ON (например, t1 ANY INNER JOIN t2 ON 1): запрос возвращал полное декартово произведение вместо результата ANY JOIN #109207 (vdimir).
  • Исправлена ошибка, из-за которой глобальное ограничение max_rows_in_join / max_bytes_in_join не соблюдалось для алгоритма JOIN parallel_hash: запрос с join_overflow_mode = 'throw' мог без ошибок завершиться успешно вместо того, чтобы выдать ошибку SET_SIZE_LIMIT_EXCEEDED. #109488 (m-selmi).
  • Исправлена скрытая потеря данных, возникавшая, когда за INSERT ... VALUES в потоке из нескольких запросов следовал завершающий SQL-комментарий (например, VALUES (1) -- comment) при разборе встроенных данных вставки на стороне сервера (send_table_structure_on_insert_with_inline_data = 0). Завершающий комментарий считывался как данные строки за пределами завершающего ;, из-за чего последующие запросы в потоке незаметно пропускались. #109643 (groeneai).
  • Исправлена работа отложенного PREWHERE при optimize_move_to_prewhere = 1, когда PREWHERE выполняется после FINAL: условия WHERE больше не переносятся впереди отложенной политики строк, что могло изменять результаты запросов. #109703 (yariks5s).
  • Исправлена ошибка LOGICAL_ERROR (query tree node does not have valid source node), возникавшая, когда рекурсивное CTE разрешало идентификатор из внешней области видимости как коррелированный столбец (при allow_experimental_correlated_subqueries = 1). Теперь такие запросы возвращают понятную ошибку UNSUPPORTED_METHOD. #109863 (groeneai).
  • Исправлено переполнение знакового целого, возникавшее, когда ORDER BY ... WITH FILL пропускает очень большой разрыв в столбце типа Int64/UInt64 (например, шаг 2 через разрыв около 2^63). При работе с санитайзерами переполнение приводило к неопределённому поведению, а в релизных сборках значения незаметно переносились по кругу. #109937 (groeneai).
  • Исправлена логическая ошибка Invalid number of rows in Chunk, возникавшая при использовании старого анализатора (enable_analyzer = 0), когда целью INTERPOLATE является псевдоним столбца WITH FILL. Теперь такие запросы отклоняются с понятной ошибкой INVALID_WITH_FILL_EXPRESSION. #110103 (groeneai).
  • Исправлена логическая ошибка (Unexpected number of columns in result sample block), возникавшая при оптимизации фильтра, содержащего коррелированный подзапрос (например, exists((SELECT ...))), с помощью convert_query_to_cnf или optimize_and_compare_chain. #110187 (alexey-milovidov).
  • Вложенный коррелированный подзапрос EXISTS, ссылающийся на столбец из области видимости за пределами непосредственно объемлющего запроса (в обход промежуточной области видимости), теперь завершается понятной ошибкой NOT_IMPLEMENTED вместо внутренней ошибки NOT_FOUND_COLUMN_IN_BLOCK. #110310 (groeneai).
  • Исправлены неверные результаты коррелированных скалярных подзапросов в случаях, когда внешний запрос содержит повторяющиеся значения коррелированного столбца, а подзапрос декоррелируется через CROSS JOIN. Ранее результаты агрегатных функций, таких как count() и sum(), умножались на число дубликатов. Исправление касается экспериментальной функциональности allow_experimental_correlated_subqueries. #110311 (groeneai).
  • Исправлена ошибка, из-за которой ORDER BY ... WITH FILL не учитывал max_execution_time и медленно отменялся при генерации большого диапазона заполнения (особенно с INTERPOLATE). #110332 (alexey-milovidov).
  • Оптимизация отложенного FINAL (query_plan_optimize_lazy_final, по умолчанию отключена) больше не применяется, если запрос читает данные в порядке ключа сортировки: заменяющий план не выдаёт строки в порядке ключа сортировки, тогда как вышестоящая часть плана после оптимизации чтения в порядке ключа может уже на это полагаться, что могло приводить к неверному порядку результатов. Она также больше не применяется, когда LIMIT, меньший числа читаемых строк, применяется непосредственно к шагу чтения: обязательный проход построения множества свёл бы на нет досрочное завершение. #110576 (KochetovNicolai).
  • Фоновый сброс на диск асинхронной вставки теперь оперативно останавливается при завершении через KILL QUERY; ранее при сбросе большого объёма буферизованных данных разбор продолжался до конца, а отмена игнорировалась. #110652 (tiandiwonder).
  • Исправлены неверные результаты GROUP BY ... optimize_aggregation_in_order и DISTINCT ... optimize_distinct_in_order, расположенных поверх JOIN типа partial_merge. Оптимизация чтения в порядке ключа распространялась через PartialMergeJoin, который пересортировывает левый вход по ключу соединения и потому не сохраняет исходный порядок левого потока, из-за чего строки группировались неправильно. #110671 (groeneai).
  • Исправлена ошибка UNKNOWN_IDENTIFIER, возникавшая при использовании псевдонимов столбцов CTE в запросах с INTERSECT или EXCEPT, например WITH t (a, b) AS (SELECT 1, 2 INTERSECT SELECT 1, 2) SELECT a, b FROM t. #110885 (yariks5s).
  • Исправлена ошибка LOGICAL_ERROR: ReadBuffer is canceled. Can't read from it., которая могла возникать в JOIN типа grace_hash, если чтение сброшенных на диск блоков завершалось сбоем посреди операции, когда несколько потоков совместно использовали объект чтения. #111056 (groeneai).
  • Исправлена ошибка, из-за которой при материализации столбцов правой стороны во время *_hash JOIN использовался неверный часовой пояс. #111074 (yariks5s).
  • Исправлены команды CREATE с секцией COMMENT: теперь при отсутствии строкового литерала комментария выдаётся синтаксическая ошибка, а не принимается молча неверно разобранный запрос (например, CREATE VIEW v COMMENT AS SELECT 1 больше не создаёт представление без комментария). #111159 (tiandiwonder).
  • Исправлена ошибка LOGICAL_ERROR (Reading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query plan), возникавшая при чтении повторно используемого материализованного CTE (enable_materialized_cte) в ветви, вывод WITH TOTALS или extremes которой отбрасывается, в том числе при внешней агрегации, INSERT ... SELECT, операциях над множествами и EXPLAIN ANALYZE. #111194 (groeneai).
  • Исправлено поведение join_algorithm = 'full_sorting_merge', при котором несоединённые строки LEFT/RIGHT/FULL/ASOFJOIN заполнялись «сырым» нулём вместо значения по умолчанию для типа столбца. Для столбца Enum (значением по умолчанию которого является его первый элемент, а не 0) это приводило к неверным результатам (фильтр по дополненному значению отбрасывал несопоставленные строки, и внешний JOIN незаметно превращался во внутренний) и к ошибке UNKNOWN_ELEMENT_OF_ENUM при выборке этого столбца. #111197 (groeneai).
  • Исправлены неверные результаты SummingMergeTree (и CoalescingMergeTree) с FINAL при optimize_move_to_prewhere_if_final = 1, когда предложение WHERE содержит неявное булево условие по столбцу ключа сортировки (например, WHERE k). Вместо того чтобы сохраняться, значение ключевого столбца суммировалось по неслитым частям. #111342 (groeneai).
  • Исправлена логическая ошибка (Unexpected number of columns in result sample block), которая могла возникать при RIGHT/FULL JOIN, если левая сторона содержит дублирующийся одноимённый столбец (например, 1 AS b, 1 AS b), сохраняющийся после UNION ALL. #111554 (groeneai).
  • Исправлен сбой клиента при форматировании запроса EXECUTE AS, в AST которого заменён дочерний узел (как это делает AST-фаззер). Теперь ASTExecuteAsQuery владеет своими дочерними узлами target_user и subquery, а не хранит невладеющие указатели на элементы children. #111725 (groeneai).
  • Исправлены неверные результаты, возникавшие, когда query_plan_join_swap_table меняет местами стороны ANY JOIN при join_any_take_last_row = 1: теперь ClickHouse сохраняет исходный порядок сторон JOIN, поэтому ANY JOIN по-прежнему возвращает последнюю совпадающую строку. #112458 (vdimir).
  • Исправлено исключение Context has expired при использовании getClientHTTPHeader внутри подзапроса. #112533 (alexey-milovidov).
  • Исправлены неверные результаты для JOIN, секция ON которого содержит смешанное условие, то есть остаточное условие неравенства между сторонами, например ON (t1.key = t2.key) AND (t1.a * 10 < t2.a). Такое условие вычисляют только алгоритмы семейства hash, однако full_sorting_merge, partial_merge и прямой JOIN типа ключ-значение заявляли о поддержке таких JOIN, а затем молча игнорировали остаточное условие и возвращали лишние строки. Теперь они отказываются от выполнения, и вместо них используется hash-алгоритм. #112831 (groeneai).
  • Исправлены неверные результаты для JOIN через запятую или CROSS JOIN, в которых предложение WHERE сравнивает столбцы двух таблиц с помощью недетерминированного выражения, например rand. Такой запрос мог возвращать строки, противоречащие его собственному предложению WHERE, поскольку при переписывании JOIN в INNER JOIN выражение переносилось в ключ JOIN, где оно повторно вычисляется для каждой строки каждой из сторон. #112938 (groeneai).
  • Исправлено квадратичное замедление при разборе запроса PromQL с длинным хвостом нераспознанных символов (например, значения FixedString, дополненного байтами NUL): разбор некорректных входных данных размером около мегабайта занимал поток на десятки минут, и его нельзя было отменить, поскольку он выполняется на этапе анализа запроса. Теперь парсер останавливается на первой же ошибке. #112944 (alexey-milovidov).
  • Исправлено поведение intDiv для непостоянного столбца с постоянным делителем -1: при делении минимального знакового числа (например, intDiv(-9223372036854775808, -1)) происходило незаметное переполнение вместо выбрасывания исключения ILLEGAL_DIVISION, как в других путях выполнения. Такое незаметное переполнение также могло приводить к неверным результатам ORDER BY/DISTINCT, поскольку оптимизация чтения в порядке сортировки корректно считает intDiv на отрицательную константу монотонной функцией, а значение после переполнения нарушало итоговый порядок сортировки. #113048 (alexey-milovidov).
  • Исправлена ошибка UNKNOWN_IDENTIFIER при enable_analyzer = 0, когда предложение WHERE ссылается на столбец, полученный с помощью untuple внутри подзапроса, например SELECT t.keys FROM (SELECT untuple(arrayJoin(m)) AS t FROM ...) WHERE t.values > 0. Переписывание запроса, выполняемое enable_optimize_predicate_expression, переносило такой предикат в подзапрос в виде HAVING, где это имя ещё не определено. #113760 (groeneai).
  • Исправлены неверные результаты JOIN с join_algorithm = 'partial_merge', когда правая сторона содержит итоговые значения (totals): правая сторона могла остаться без слияния, из-за чего LEFT JOIN подставляли значения по умолчанию вместо реальных совпадений, а INNER/RIGHT JOIN вообще не возвращали строк. При обработке несовпавших строк для RIGHT/FULL то же состояние приводило к разыменованию нулевого указателя и аварийному завершению сервера. #113936 (groeneai).
  • Исправлены неверные результаты SELECT DISTINCT с LIMIT, которому необходимо прочитать все входные данные: LIMIT n WITH TIES отбрасывал строки с равными значениями, exact_rows_before_limit = 1 возвращал усечённое значение rows_before_limit_at_least, а GROUP BY ... WITH TOTALS вычислял строку итогов лишь по начальной части потока. #114025 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR («Unexpected number of kept output positions after removing unused columns from ReadFromMergeTree»), возникавшая в запросе SELECT ... FINAL, в котором PREWHERE использует столбец, необходимый FINAL для слияния (ver, is_deleted, sign), но сам этот столбец не выбирается. #114746 (groeneai).
  • Исправлена проблема времени жизни объектов при сбросе буфера асинхронных INSERT, обработке материализованных представлений и выполнении EXPLAIN ANALYZE, из-за которой могло происходить обращение к уже освобождённому состоянию отслеживания запроса. #114940 (azat).
  • Исправлено поведение CREATE QUOTA и ALTER QUOTA, которые без каких-либо сообщений отбрасывали все блоки FOR INTERVAL, кроме последнего, если между интервалами не была указана разделяющая запятая. Такой оператор выполнялся успешно, но не устанавливал ни одного из предшествующих ограничений. Теперь интервалы снова накапливаются, как это было до 2020 года. #115320 (groeneai).
  • Исправлена ошибка, из-за которой randConstant возвращала два разных значения в одном запросе, если её вызовы имели разные псевдонимы. Согласно документации, randConstant возвращает одно и то же значение в пределах всего запроса, и SELECT randConstant() = randConstant() уже возвращал 1, однако при добавлении псевдонимов, как в SELECT randConstant() AS a, randConstant() AS b, получались два никак не связанных значения. #115384 (alexey-milovidov).
  • Исправлена ошибка, из-за которой SELECT count() для повреждённого файла MsgPack или ProtobufList либо никогда не завершался, либо возвращал выдуманное количество строк. Быстрый путь optimize_count_from_files подсчитывал строки, не проверяя, что позиция чтения сдвигается, поэтому двухбайтовый файл ProtobufList давал миллиарды строк, и запрос так и не завершался. Теперь такие входные данные отклоняются с той же ошибкой, что и при обычном пути чтения. #115884 (groeneai).
  • Исправлена ошибка, из-за которой broken_data_files в system.distribution_queue и метрика BrokenDistributedFilesToInsert всегда показывали 0: при сканировании очереди асинхронных вставок во время запуска сервера DistributedAsyncInsertDirectoryQueue::initializeFilesFromDisk учитывала повреждённые байты, но не увеличивала счётчик повреждённых файлов. #92124 (squalfof).

Прочие исправления ошибок

  • Вторичные запросы, выполняемые в рамках внутренних запросов, теперь записываются в журнал как внутренние запросы. #108506 (mstetsyuk).
  • Исправлена ошибка, из-за которой отсутствующий в части DEFAULT-столбец заполнялся значением по умолчанию для типа вместо DEFAULT-выражения, если условие PREWHERE разбивалось на несколько шагов чтения. #111795 (yariks5s).
  • Квоты с ключом normalized_query_hash теперь учитывают все ресурсы (read_rows, read_bytes, result_rows, result_bytes, execution_time, written_bytes, errors) отдельно для каждого шаблона запроса — так же, как счётчики количества запросов, — а не в едином общем бакете на пользователя. #107681 (alexey-milovidov).
  • Исправлена ошибка, из-за которой не действовали connect_timeout, а также тайм-ауты чтения и записи MySQL: попытка соединения с не отвечающим сервером MySQL могла зависать более чем на две минуты даже при connect_timeout = 1, поскольку периодические сигналы выборочного профилировщика запросов постоянно сбрасывали внутренний дедлайн опроса в клиенте MySQL. #109592 (tiandiwonder).
  • Исправлена ошибка, из-за которой тайм-аут ожидания блока при потоковых вставках (input_format_max_block_wait_ms) мог никогда не истекать при активном профилировщике запросов: опрос файлового дескриптора перезапускался с полным тайм-аутом после каждого сигнала профилировщика, поэтому зависший источник входных данных мог бесконечно откладывать сброс частичного блока, вместо того чтобы сбросить его по достижении лимита ожидания. #109602 (tiandiwonder).
  • Исправлена ошибка LOGICAL_ERROR (std::length_error), возникавшая, когда в запросе с экспериментальной настройкой make_distributed_plan = 1 использовалось очень большое значение distributed_plan_default_reader_bucket_count или distributed_plan_default_shuffle_join_bucket_count. Теперь такие значения отклоняются с ошибкой INVALID_SETTING_VALUE. #109770 (groeneai).
  • Исправлена работа distinct_overflow_mode = 'break': DISTINCT теперь возвращает частичный результат, накопленный до достижения лимита, и прекращает чтение источника, как указано в документации. Ранее фрагмент, на котором превышался max_rows_in_distinct / max_bytes_in_distinct, отбрасывался (результаты получались усечёнными или пустыми), а запрос продолжал читать данные и вставлять их в хеш-множество до конца входных данных, что могло привести к ошибке MEMORY_LIMIT_EXCEEDED. #110075 (skuznetsov-clickhouse).
  • Исправлена ошибка, из-за которой optimize_aggregation_in_order игнорировала отмену запроса. AggregatingInOrderTransform теперь проверяет отмену во время агрегации фрагмента, поэтому запрос, остановленный с помощью KILL QUERY или по max_execution_time (при значении по умолчанию timeout_overflow_mode = 'throw'), завершается сразу, а не после обработки всего фрагмента. #110104 (groeneai).
  • Исправлено аварийное завершение сервера (в отладочных сборках и сборках с санитайзерами) при чтении значения из PostgreSQL-источника семейства mysql/postgresql/sqlite в объявленный тип, к которому это значение невозможно привести при разборе (например, столбец text, объявленный как Int32). Теперь о таком несоответствии типов сообщается как об ошибке запроса, и сервер не завершается аварийно. #110264 (groeneai).
  • Исправлено аварийное завершение сервера при разборе некоторых запросов PRQL (SET dialect = 'prql'). Паника внутри компилятора prqlc приводила к аварийному завершению процесса, вместо того чтобы возвращаться как ошибка запроса. #110316 (groeneai).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK, возникавшая, когда политика строк и additional_table_filters ссылаются на один и тот же столбец, который больше нигде в запросе не выбирается. #111099 (groeneai).
  • Исправлено зависание randChiSquared, randStudentT, randFisherF и randBinomial при экстремальных значениях параметров. Такой запрос невозможно было прервать ни с помощью max_execution_time, ни с помощью KILL QUERY. Теперь подобные параметры отклоняются, даже если max_rand_distribution_parameter или max_rand_distribution_trials установлены в 0, а значение max_rand_distribution_trials для randBinomial больше нельзя поднять выше значения по умолчанию 10^9. #111909 (alexey-milovidov).
  • Исправлена работа connection_pool_max_wait_ms: указанное в документации значение по умолчанию 0 теперь действительно означает бесконечный тайм-аут. Ранее запрос, обнаружив, что пул соединений заполнен, повторял попытки в плотном цикле, нагружая CPU и записывая в лог No free connections in pool. Waiting 0 ms. на каждой итерации. Теперь он ждёт, пока соединение не вернётся в пул. #112380 (groeneai).
  • Исправлена проблема, из-за которой replaceOne, replaceAll, replaceRegexpOne и replaceRegexpAll игнорировали max_execution_time и KILL QUERY. Теперь даже отдельный вызов проверяет отмену в процессе работы, поэтому длительная замена в большом значении или в большом количестве строк прерывается, а не занимает поток сервера до своего завершения. Частичного результата у такого вызова нет, поэтому при timeout_overflow_mode = 'break' превышение лимита времени выдаётся как ошибка: всегда при свёртке констант, а в конвейере — всякий раз, когда эта контрольная точка достигается раньше межблочной проверки исполнителя, которая по-прежнему останавливает запрос без ошибки. #112483 (groeneai).
  • Исправлена проблема, из-за которой countSubstrings, countSubstringsCaseInsensitive и countSubstringsCaseInsensitiveUTF8 игнорировали KILL QUERY и max_execution_time: вызов на большом числе строк или совпадений мог выполняться ещё несколько минут после отмены запроса. #113369 (groeneai).
  • Исправлено возможное зависание запроса (на receive_timeout секунд), если он очень быстро завершается на узле-initiator. #113551 (nickitat).
  • Исправлена проблема, из-за которой countMatches и countMatchesCaseInsensitive игнорировали max_execution_time и KILL QUERY при подсчёте совпадений в одном большом значении, и отменённый запрос продолжал выполняться ещё несколько минут. При константном аргументе вызов происходит на этапе анализа запроса, когда конвейера, который мог бы его отменить, ещё нет. #113886 (groeneai).
  • Запрос мог быть отменён раньше истечения max_execution_time (вплоть до 1 мс) с противоречивой ошибкой Timeout exceeded: elapsed 999.672 ms, maximum: 1000 ms. #114559 (alexey-milovidov).
  • Исправлено чтение за пределами буфера в pointInPolygon при константном полигоне с неограниченным ограничивающим прямоугольником, например когда координата достигает +-DBL_MAX. Теперь такой полигон отклоняется с ошибкой BAD_ARGUMENTS, а полигон с пустым кольцом считается не имеющим внутренней области. Ранее запрос мог вернуть неверный результат или аварийно завершить сервер в сборках с усиленной защитой (hardening) или санитайзерами. #115035 (groeneai).
  • Исправлено состояние гонки, из-за которого запрос STREAM BOUNDED мог вернуть меньше строк, чем было закоммичено до его запуска (как правило, ни одной). #115543 (alexey-milovidov).
  • Исправлена ошибка Unknown identifier, возникавшая при оптимизации плана запроса с make_distributed_plan = 1, когда столбец сортировки оконного запроса проходит через шаг Expression, в котором он не упоминается. #115890 (groeneai).
  • Исправлена ошибка, из-за которой h3kRing, h3HexRing, h3Line и h3ToChildren игнорировали max_execution_time и KILL QUERY при развёртывании блока строк. #115893 (alexey-milovidov).
  • Исправлена ошибка NOT_FOUND_COLUMN_IN_BLOCK в нативном считывателе Parquet V3 (появившаяся в результате предыдущей регрессии), возникавшая, когда в условии PREWHERE были конъюнкты с общим промежуточным выражением. #107059 (groeneai).
  • Исправлено зависание при записи Parquet с включённым параметром output_format_parquet_parallel_encoding (включён по умолчанию) и значением max_threads больше 1. Если кодировщику не удавалось запланировать дополнительный поток, счётчик активных потоков выходил за нижнюю границу диапазона, и запись могла навсегда остановиться, вместо того чтобы завершиться или сообщить об ошибке. #112959 (groeneai).
  • Исправлено неограниченное выделение памяти при чтении файла Parquet, в метаданных Thrift которого объявлена длина контейнера или строки, превышающая размер самих метаданных. Теперь такая длина отклоняется, и память под неё не выделяется. #113212 (groeneai).
  • Исправлено исключение std::out_of_range (Logical error: 'std::exception. Code: 1001, type: std::out_of_range', которое в отладочных сборках и сборках с санитайзерами также приводит к аварийному завершению сервера) в считывателе Parquet v3, возникавшее, когда столбец, нужный только для вычисления фильтра, ставился в очередь на декодирование уже после удаления его выходного слота. #113956 (groeneai).
  • Исправлены гонки данных в profile events и трекере памяти. #112466 (mstetsyuk).
  • Исправлена теоретически возможная гонка данных в profile events при использовании настройки trace_profile_events_list для записи трассировок стека определённых profile events в system.trace_log. #113553 (mstetsyuk).
  • Исправлена ошибка, из-за которой intDivOrNull, moduloOrNull и positiveModuloOrNull возвращали 0 вместо NULL, а intDivOrNull и intDivOrZero выбрасывали исключение вместо того, чтобы вернуть NULL / 0, когда деление приводило к исключению с плавающей запятой (деление на ноль или INT_MIN / -1), в том числе для смешанных знаковых и беззнаковых аргументов. #101976 (yariks5s).
  • Исправлена работа IS DISTINCT FROM для значений Array и Map при сравнении с NULL. #103162 (ylw510).
  • Исправлена работа groupConcat при смешивании параметрической и двухаргументной форм записи, например groupConcat(',', 2)(x, '/'): параметр ограничения числа строк молча отбрасывался, и вместо запрошенного количества возвращались все строки; теперь разделитель из второго аргумента корректно переопределяет параметр. #104882 (yariks5s).
  • Исправлены ошибки при использовании CAST для преобразования из меньших единиц интервала в большие. #105058 (yariks5s).
  • Исправлена логическая ошибка (Assertion 'row < chunk.getNumRows()' failed) в запросах LIMIT ... WITH TIES, выполняемых с конвейером чтения в порядке сортировки (optimize_read_in_order = 1 и read_in_order_use_virtual_row_per_block = 1). #105102 (groeneai).
  • Исправлена ошибка Logical error: 'Pipeline stuck' в запросах, использующих enable_sharding_aggregator = 1 вместе с UNION ALL и значением max_streams_for_union_step, меньшим ширины конвейера. BufferedShardByHashTransform теперь закрывает выходные порты с пустыми очередями сразу после того, как входные данные исчерпаны, и продолжает считывать входные данные, если запрошенному пустому порту нечего выдать, даже когда соседняя очередь достигла предела обратного давления (back-pressure). #106251 (groeneai).
  • Исправлено поведение removeDirectory на дисках объектного хранилища типа plain (например, s3_plain): при удалении непустого каталога удалялись все файлы внутри него, как если бы удаление было рекурсивным. Теперь попытка удалить непустой каталог завершается ошибкой CANNOT_RMDIR, а при рекурсивном удалении содержимое обрабатывается явно. #106281 (RinChanNOWWW).
  • Исправлена проблема, из-за которой пользовательские функции типа executable_pool, настроенные с <lifetime>, не подхватывали изменения в исходном скрипте. Ранее изменённый скрипт перечитывался только командой SYSTEM RELOAD FUNCTIONS, а при периодических перезагрузках по <lifetime> продолжала выполняться старая версия. #107087 (groeneai).
  • Исправлена гонка данных в глобальном сборщике трассировок сервера между запуском профилировщика в рабочем потоке и остановкой сервера. #107307 (groeneai).
  • Исправлено редкое аварийное завершение сервера при остановке (std::future_error, “The associated promise has been destructed prior to the associated state becoming ready”), возникавшее из-за того, что задача, запланированная через threadPoolCallbackRunnerUnsafe, удалялась из очереди пула потоков до своего выполнения. #107383 (groeneai).
  • Исправлена логическая ошибка FileLog (Last stored last_written_position in meta file ... is bigger than current last_written_pos), которая могла возникать, если отслеживаемый файл удалялся и создавался заново с тем же inode. #107617 (groeneai).
  • Исправлена проблема, из-за которой toTime64 и CAST(... AS Time64) в режимах обработки переполнения saturate и ignore не приводили значения, выходящие за пределы диапазона Time64, к его границам. Из-за этого могли получаться значения, которые отображаются одинаково, но при сравнении считаются разными. #108028 (alexey-milovidov).
  • Исправлена некорректная обработка утверждений нулевой ширины (\b, ^, $) в функциях regexp, ищущих все совпадения: extractAll, extractAllGroupsVertical, extractAllGroupsHorizontal, countMatches и splitByRegexp. Например, extractAll('new york is the greatest', '\b(\w)') теперь корректно возвращает первую букву каждого слова, а не все буквы подряд. #108047 (alexey-milovidov).
  • Исправлены некорректные результаты hasToken при использовании текстовых индексов с токенизатором, отличным от splitByNonAlpha. #108066 (rschu1ze).
  • Исправлена проблема, из-за которой toStartOfInterval и dateTrunc возвращали округлённое значение вместо начала интервала, в который попадает входное значение, если точность входного значения была выше единицы интервала. Например, toStartOfInterval(toDateTime64('2023-10-09 10:11:12.000999', 6), INTERVAL 1 millisecond) возвращал 10:11:12.001 вместо 10:11:12.000. Ошибка затрагивала и перегрузку с явно заданной точкой отсчёта. #108186 (yariks5s).
  • Исправлены функции replaceRegexpOne и replaceRegexpAll: теперь . по умолчанию соответствует символам перевода строки, как и в других функциях для работы с регулярными выражениями. #108265 (linjiayu1025-collab).
  • Исправлено двойное вычисление условий в легковесных UPDATE/DELETE. #108323 (ofeliacode).
  • Исправлена работа arrayPartialSort() с неконстантным аргументом limit. #108327 (vitlibar).
  • Исправлены функции для работы с регулярными выражениями (match, extract, extractAll, replaceRegexpOne, replaceRegexpAll и др.), которые молча возвращали неверные результаты, если шаблон регулярного выражения содержал байт NUL (\0). Теперь NUL обрабатывается как обычный литеральный байт, что соответствует поведению RE2. #108427 (alexey-milovidov).
  • Исправлена ошибка, из-за которой changeYear/changeMonth/changeDay/changeHour/changeMinute/changeSecond с аргументом DateTime64(N) создавали результирующий столбец с жёстко заданным масштабом по умолчанию (3) вместо N. Значения вычислялись с масштабом N, однако в объекте столбца был объявлен масштаб 3, из-за чего столбец оказывался структурно несогласованным со своим типом. #108551 (groeneai).
  • Исправлена ошибка LOGICAL_ERROR («Trying to extract chunk from ChunkBuffer before all inputs are finished»), возникавшая, когда операция над множествами (INTERSECT / UNION ALL / EXCEPT) объединяла ветви с коррелированными подзапросами при correlated_subqueries_default_join_kind = 'left'. #108554 (groeneai).
  • Исправлены ошибки при работе с DateTime64 в changeYear, changeMonth, changeDay, changeHour, changeMinute и changeSecond: входные значения с наносекундной точностью (масштаб 9) больше не вызывают DECIMAL_OVERFLOW, а для значений с долями секунды до начала эпохи теперь возвращается правильная календарная секунда. #108681 (takumihara).
  • Устранены избыточный вывод в лог сервера и чрезмерно большое сообщение об ошибке при компиляции очень большого регулярного выражения (например, шаблона LIKE или match с сотнями тысяч подстановочных символов); теперь такие шаблоны завершаются понятной ошибкой CANNOT_COMPILE_REGEXP. #108821 (Algunenano).
  • Исправлена ошибка, из-за которой reinterpret(x, 'Decimal128(scale)') (а также с целевыми типами Decimal32/Decimal64/Decimal256/DateTime64) создавал результирующий столбец, внутренний масштаб которого совпадал с исходным, а не с запрошенным целевым масштабом, если исходный и целевой типы имели одинаковое физическое представление. Значения были корректными, однако объект столбца был структурно несогласован с объявленным типом. #108878 (groeneai).
  • Исправлено неопределённое поведение при преобразовании в строку типа пакета протокола, выходящего за допустимый диапазон (например, в сообщениях об ошибках «Unexpected packet from server» / «Received … packet»), при рассинхронизированном соединении или при фаззинге. #108885 (groeneai).
  • Исправлена ошибка, из-за которой changeYear/changeMonth/changeDay/changeHour/changeMinute/changeSecond для DateTime64(N) формировали результирующий столбец с жёстко заданным масштабом по умолчанию 3 вместо N, а timeSlots для DateTime64 не учитывала масштаб необязательного аргумента Size в объявленном типе возвращаемого значения. В обоих случаях физический масштаб получаемого столбца расходился с объявленным типом, что приводило к LOGICAL_ERROR (writeSlice expects same column types) при передаче результата в arrayPushBack/arrayPushFront/arrayConcat, а timeSlots с наибольшим масштабом в Size возвращала неверные временные метки. #108994 (groeneai).
  • Исправлены немонотонные приращения ProfileEvents #109180 (azat).
  • Исправлена ошибка, из-за которой коэффициенты SAMPLE с показателем степени, модуль которого выходит за пределы Int32 (например, SAMPLE 1e-3000000000), без каких-либо предупреждений обрабатывались как SAMPLE 1. #109197 (Algunenano).
  • Исправлены две ошибки при обработке DateTime64 в toUTCTimestamp/fromUTCTimestamp (и их псевдонимах to_utc_timestamp/from_utc_timestamp) и toTime64. Во-первых, переполнение знакового целого вблизи границы Int64 (теперь вычисление выполняется в Int128, а результат ограничивается допустимым диапазоном). Во-вторых, неверный результат для отрицательных дробных значений вблизи границы смены смещения часового пояса: при выделении секунд выполнялось усечение к нулю, поэтому timezoneOffset() проверяла следующую секунду и могла оказаться не по ту сторону перехода на летнее время (DST) или смены смещения. #109738 (groeneai).
  • Исправлена логическая ошибка (column->size() == num_rows), возникавшая, если выражение фильтра row policy использует arrayJoin; такие фильтры теперь отклоняются. #109753 (Algunenano).
  • Исправлена ошибка, из-за которой generateRandomStructure() иногда формировала некорректную строку структуры с двумя слитными типами данных (например, Decimal32(7)IPv4), если вложенность типов превышала внутренний предел глубины; такой результат невозможно было разобрать. #109928 (groeneai).
  • Исправлена передача настроек запроса в accurateCastOrDefault и сохранение исходных значений NULL, закодированных в Dynamic и Variant. #109946 (Avogar). #114912 (alexey-milovidov).
  • Исправлены max_bytes_in_distinct и max_bytes_in_set: строковые ключи хранятся в арене, которая не учитывалась при проверке ограничений, поэтому DISTINCT / IN по строковым ключам могли занимать память сверх лимита в байтах на весь объём данных ключей (без ограничения сверху, в зависимости от длины ключа). Теперь ограничения учитывают арену, как и указано в документации; запросы со строковыми ключами, приближающиеся к лимиту в байтах, теперь могут превышать его раньше (что корректно). #110120 (skuznetsov-clickhouse).
  • Исправлено чтение файлов Npy с внутренними размерностями нулевого размера: теперь материализованные строки и результаты оптимизированного и неоптимизированного count() совпадают. #110146 (qiuyanjun888).
  • Исправлена логическая ошибка (аварийное завершение сервера в отладочных сборках и сборках с санитайзерами), возникавшая, если функциям indexHint/ignore/isZeroOrNull передавался аргумент, тип которого разрешается в Nothing, например в выражениях вида indexHint(assumeNotNull(materialize(NULL))). #110192 (groeneai).
  • Исправлено чтение файлов на дисках plain_rewritable после перезаписи существующего пути содержимым другого размера: в метаданных в памяти оставался устаревший размер файла, из-за чего чтение могло завершаться ошибкой UNEXPECTED_END_OF_FILE. #110304 (thevar1able).
  • Значения vector_search_index_fetch_multiplier меньше 1.0 теперь отклоняются: это предотвращает пустые результаты ANN-поиска в случаях, когда вычисленное количество извлекаемых записей при усечении обращается в ноль. #110452 (tamish560).
  • Исправлена эпизодически возникающая ошибка Cannot parse string ... as UInt64 ... While executing ValuesBlockInputFormat, которая могла появляться при вставке значений, чьи выражения содержат числовое приведение типа, например initializeAggregation('sumState', 0::UInt64). #110637 (groeneai).
  • Функция readWKT больше не отклоняет WKT-строки с начальными пробельными символами (например, readWKT(' POINT(1 2)')), которые принимаются типизированными считывателями readWKTPoint/readWKTPolygon/… и допускаются грамматикой WKT. #110706 (groeneai).
  • Исправлено аварийное завершение сервера (целочисленное деление на ноль) при расходовании квоты с интервалом нулевой длины (например, CREATE QUOTA q FOR INTERVAL 0 SECOND MAX queries = 1000). Теперь неположительная длительность интервала квоты отклоняется уже при создании квоты. #110846 (PedroTadim).
  • Исправлено аварийное завершение в FIPS-сборках при использовании SSH-ключа Ed25519 (CREATE USER ... IDENTIFIED WITH ssh_key ... TYPE 'ssh-ed25519' или такого ключа в users.xml). Ed25519 не входит в число алгоритмов, одобренных FIPS, поэтому такие ключи теперь отклоняются с понятной ошибкой LIBSSH_ERROR. #110891 (thevar1able).
  • Транспонированные функции расстояния над QBit (cosineDistanceTransposed, L2DistanceTransposed, dotProductTransposed) теперь используют ограниченное восстановление с низкой точностью для значения, усечённого до precision битовых плоскостей, вместо восстановления до нижней границы грубой ячейки (с заполнением отброшенных битов нулями). Заполнение нулями смещало каждое восстановленное значение к нулю и при низкой точности приводило к вырожденному результату: для QBit(BFloat16) при точности 1 сохраняется только знаковый бит, поэтому любое значение восстанавливалось в ±0.0, а расстояние для всех строк было одной и той же константой и не несло никакой информации для ранжирования. Теперь способ восстановления зависит от того, какие биты отбрасываются: необработанные коды Int8 восстанавливаются к центру своей ячейки (что соответствует восстановлению по методу Lloyd-Max, уже применявшемуся в пути ...TransposedQuantized); значение с плавающей запятой при точности 1 превращается в полноценное знаковое квантование; значение с плавающей запятой, у которого сохраняется весь порядок, а отбрасываются только биты мантиссы, восстанавливается к ограниченной средней точке своей бинады (при этом настоящий ноль или ±0.0 остаётся точным нулём, а ячейка неконечных значений выделяется отдельно, чтобы ±inf оставалась точной бесконечностью; о неоднозначной ячейке NaN см. примечание ниже); пока же усекаются биты порядка, сохраняется ограниченная нижняя граница, так что меньшее значение precision позволяет пожертвовать точностью ради скорости, не завышая величину на порядки. Результаты с полной точностью не изменились. #110911 (alexey-milovidov).
  • Исправлено чтение за пределами допустимого диапазона в нативном считывателе ORC при выводе схемы повреждённого ORC-файла, в дереве типов которого объявлено больше столбцов, чем имеется кодировок столбцов в футере страйпа. Теперь такой файл отклоняется с ошибкой CANNOT_EXTRACT_TABLE_STRUCTURE, а не приводит к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами. #110967 (groeneai).
  • Каждый SSH-ключ теперь учитывается отдельно в лимите max_authentication_methods_per_user, поэтому лимит применяется единообразно независимо от синтаксиса. Ранее несколько ключей в одном методе ssh_key считались за один. #111181 (TheMC47).
  • REST-каталоги Iceberg теперь сообщают об устаревших учётных данных с указанием исходной ошибки, а не молча возвращают UNKNOWN_TABLE. #111379 (alesapin).
  • Исправлена ошибка, из-за которой readWKTPoint/readWKT возвращали неинициализированные (в скалярном режиме) или взятые из предыдущей строки (в векторизованном режиме) координаты для пустой точки с тегом размерности, например POINT M EMPTY. Теперь такие входные данные отклоняются с ошибкой CANNOT_PARSE_TEXT — так же, как и POINT EMPTY. #111517 (groeneai).
  • При создании статистики minmax теперь выводится предупреждение, а не генерируется исключение. #111785 (hanfei1991).
  • Функция randBinomial теперь корректно работает с вырожденными вероятностями 0 и 1 при любом числе испытаний. #112021 (alexey-milovidov).
  • Исправлена ошибка, из-за которой system.s3_queue_settings показывала неверные значения для bucketing_mode, partitioning_mode, partition_regex и partition_component. #112300 (bharatnc).
  • Теперь для ошибок в запросах PromQL указывается правильная позиция. #112494 (fallintoplace).
  • SYSTEM DISABLE FAILPOINT теперь отклоняет имя несуществующего fail point с ошибкой BAD_ARGUMENTS, как это уже делала SYSTEM ENABLE FAILPOINT. Ранее при опечатке в имени команда сообщала об успехе, оставляя нужный fail point включённым и никак не указывая, что ничего не было отключено. #112680 (groeneai).
  • Исправлено чтение с неверным типом подстолбца элемента Nested, столбец которого был удалён и добавлен заново. При выборке такого подстолбца вместе с его родительским столбцом на месте подстолбца возвращался весь элемент, хотя в блоке по-прежнему был объявлен тип элемента; это приводило к произвольным значениям в релизных сборках и к логической ошибке в отладочных сборках и сборках с санитайзерами. #112769 (groeneai).
  • Теперь отклоняются длительности PromQL, в которых единицы измерения повторяются или не упорядочены от наибольшей к наименьшей. #112954 (fallintoplace).
  • Исправлено неопределённое поведение (передача нулевого указателя в memcpy) в replaceRegexpOne/replaceRegexpAll, когда строка замены подставляет захватывающую группу, не участвовавшую в совпадении, например replaceRegexpAll('abc', '(a)|(b)', '\\2'). #113012 (alexey-milovidov).
  • Исправлена несовместимость, из-за которой текстовые индексы, созданные в ClickHouse 26.3 с токенизатором unicode_word, не загружались в более поздних версиях #113061 (rschu1ze).
  • Теперь отклоняются недопустимые суррогатные кодовые точки Unicode в escape-последовательностях строк PromQL. #113203 (fallintoplace).
  • Теперь отклоняется недопустимое экранирование разделителей другого типа в строках PromQL. #113587 (fallintoplace).
  • Исправлена ошибка, из-за которой theilsU в рамке окна возвращала произвольное значение вместо 0, если первый аргумент постоянен в пределах рамки окна. #113691 (alexey-milovidov).
  • Исправлен код ошибки, возвращаемый для некоторых некорректных столбцов, сериализованных как Replicated и полученных по собственному протоколу: теперь они отклоняются с INCORRECT_DATA вместо LOGICAL_ERROR (что приводило к аварийному завершению сервера в отладочных сборках и сборках с санитайзерами). #114186 (Avogar).
  • Исправлены некорректные (часто с инвертированным знаком) литералы Time64 и константы в списках IN, возникавшие при переполнении Int64 во время масштабирования Decimal64 с меньшим масштабом. Теперь при таком преобразовании выдаётся ошибка DECIMAL_OVERFLOW — так же, как в ветке DateTime64 и при явном CAST. #114546 (groeneai).
  • Добавлена поддержка имён метрик и меток в кавычках в селекторах PromQL. #114551 (fallintoplace).
  • Исправлена ошибка, из-за которой таблицы ReplicatedMergeTree неограниченно долго оставались в режиме только для чтения после неудачной попытки запуска, выполнявшейся через поток присоединения. Теперь повторный перезапуск планируется корректно, благодаря чему снова работают автоматическое восстановление и связанные с ним проверки сессии. #114802 (azat).
  • timeSeriesRange и timeSeriesFromGrid выдавали ложную ошибку DECIMAL_OVERFLOW для временных меток до 1970 года, поскольку начальная и конечная временные метки считывались как беззнаковые значения. Кроме того, для временных меток DateTime/UInt32 шаг молча усекался до младших 32 бит. Теперь все вычисления выполняются в Int64. #114815 (vitlibar).
  • Исправлено возможное исключение в асинхронных вставках после сбоя запроса с MEMORY_LIMIT_EXCEEDED, а также исправлена работа настройки async_insert_queue_flush_on_shutdown: теперь вставки из очереди сбрасываются на диск при остановке сервера. #114839 (azat).
  • Исправлено исключение out_of_range, выбрасываемое как внутренняя ошибка Code: 1001, когда шаблон sequenceMatch, sequenceCount или sequenceMatchEvents содержит номер события 0, например sequenceMatch('(?0)'). Теперь такой шаблон отклоняется с BAD_ARGUMENTS. Временное условие, содержащее только знак, например sequenceMatch('(?1)(?t>+)(?2)'), молча интерпретировалось как (?t>0), а теперь отклоняется с SYNTAX_ERROR. #115056 (groeneai).
  • Исправлено сообщение об ошибке geoToH3, в котором указывались неверная позиция аргумента и неверный тип, если координата не имеет тип Float64. При значении по умолчанию geotoh3_argument_order = 'lat_lon' сообщение указывало на другой аргумент и выводило его тип. #115503 (groeneai).
  • Исправлены некорректные escape-последовательности с обратной косой чертой в индексах text, tokenbf_v1 и ngrambf_v1. #115634 (ahmadov).
  • Исправлена проблема: сервер не запускался, если переменная окружения TZ была пустой. #68921 (ardenwick).
Последнее изменение 14 октября 2026 г.