Экспериментальный статус
Основной клиент, источник данных, сеанс, интерфейсы операций и расширения для внедрения зависимостей вызывают предупреждение компилятораCHTCP0001. Чтобы подавить это предупреждение на время ознакомления с API, добавьте его
в NoWarn в файле проекта:
Поддерживаемые версии .NET
Нативный TCP-клиент поддерживает следующие версии .NET:- .NET 8.0
- .NET 9.0
- .NET 10.0
Поддерживаемые версии ClickHouse
TCP-клиент официально поддерживает две последние LTS-версии и три последних релиза сервера ClickHouse.Установка
Нативный TCP-клиент входит в пакетClickHouse.Driver. Установите его из NuGet:
Быстрый старт
Переход с HTTP-клиента
TCP API не связан сIClickHouseClient: TCP нельзя выбрать в качестве транспортного протокола для
ClickHouseClient или ClickHouseConnection. Большинство SQL-запросов можно использовать без изменений, но потребуется создать
ClickHouseTcpClient и заменить каждую операцию её аналогом для TCP.
Соответствия методов
Например, цикл чтения через HTTP-клиент:
Параметры и аргументы
HTTP-версииQueryOptions и ClickHouseParameterCollection не взаимозаменяемы с их аналогами
для TCP. Перенесите значения в ClickHouseTcpQueryOptions: в нём настройки задаются строками, а
аргументы входят в объект параметров:
{name:Type}, встроенные в ClickHouse, но не преобразует
плейсхолдеры @name в стиле ADO.NET. Кроме того, для отдельных запросов нельзя задать базу данных, роль, Bearer-токен или пользовательский
заголовок; также не поддерживаются средство разрешения или форматтер параметров и преобразователь данных при чтении. Подробнее о
возможностях, доступных только через HTTP, см. в разделе «Ограничения».
Время жизни соединения и результата
Оба высокоуровневых клиента потокобезопасны, поэтому их следует использовать повторно. TCP-клиент управляет постоянными соединениями по нативному протоколу, а не HTTP-соединениями, реализуетIAsyncDisposable и обычно должен
асинхронно освобождаться при завершении работы приложения.
Строки, возвращаемые QueryAsync, принадлежат вызывающему коду. Блоки StreamAsync и их столбцы не принадлежат вызывающему коду и доступны
только во время текущей итерации; значения, которые понадобятся позже, необходимо скопировать. Всегда завершайте перебор или освобождайте
его ресурсы, чтобы соединение вернулось в пул. Используйте OpenSessionAsync, если несколько операций
должны выполняться через одно соединение с сохранением состояния сеанса.
Полный
пример миграции с HTTP на TCP
показывает, как оба клиента работают с одной таблицей.
Конфигурация
Нативный TCP-клиент можно настроить двумя способами:- Строка подключения: пары «ключ — значение», разделённые точкой с запятой и задающие конечную точку сервера, учётные данные для аутентификации и другие параметры соединения.
- Объект
ClickHouseTcpClientOptions: строго типизированный неизменяемый объект конфигурации, задаваемый в коде.
ClickHouseTcpClient. Используйте
ClickHouseTcpConnectionStringBuilder, чтобы разобрать или создать строку подключения и преобразовать её в
ClickHouseTcpClientOptions.
Настройки соединения
Значения свойствTimeSpan в строке подключения задаются в секундах.
Формат данных и сериализация
Пул соединений
Одно соединение может выполнять только одну операцию за раз. Пул позволяет выполнять операции параллельно и повторно использовать соединения для разных операций.Безопасность
Для защищённого собственного протокола используется отдельная конечная точка сервера: переключиться
на TLS в рамках уже установленного соединения нельзя. Клиент с TLS должен подключаться к защищённому
порту собственного протокола; перехода на соединение без шифрования не происходит.
ConfigureTls
применяется последним и может переопределить проверку сертификата и имени хоста, поэтому тщательно
проверяйте пользовательские функции обратного вызова.
Логирование и отладка
Логгер клиента записывает события жизненного цикла и операций на стороне клиента. Пакеты серверного журнала вместо этого передаются
в
ClickHouseTcpQueryCallbacks.OnLog. Текст оператора может содержать конфиденциальные данные, поэтому по умолчанию он
не включается в теги активности, а в отладочных журналах существенно обрезается.
Пользовательские настройки
ClickHouseTcpClientOptions.CustomSettings применяет настройки сервера ClickHouse к каждому запросу и
каждой вставке. Значения ClickHouseTcpQueryOptions.Settings, заданные для конкретной операции, переопределяют одноимённые настройки на уровне клиента.
set_:
set_ при добавлении настройки в CustomSettings или в Settings отдельной
операции.
ClickHouseTcpQueryOptions
ClickHouseTcpQueryOptions задаёт настройки для отдельной операции. Все свойства необязательны.
ClickHouseTcpInsertOptions
ClickHouseTcpInsertOptions расширяет ClickHouseTcpQueryOptions настройками для вставки
нативных блоков. Все свойства параметров запроса также доступны.
ClickHouseTcpClient
ClickHouseTcpClient — высокоуровневый API для собственного TCP-протокола. Он выполняет команды и
скалярные запросы, передаёт результаты потоком в виде столбцовых блоков, строк или объектов POCO, вставляет данные по столбцам или строкам
и открывает сеансы, закреплённые за соединением.
Клиент потокобезопасен и управляет пулом соединений. Создайте по одному клиенту для каждой конечной точки, используйте его
во всём приложении и освобождайте его ресурсы при остановке. Одновременно может выполняться до
MaxPoolSize операций; остальные ожидают свободного соединения не дольше PoolTimeout.
Создание клиента
Создайте клиент, используя строку подключения илиClickHouseTcpClientOptions. Доступные параметры см. в разделе
Конфигурация.
Создание клиента с помощью строки подключения:
PoolTimeout, после чего прерывает их.
Внедрение зависимостей
AddClickHouseTcpDataSource регистрирует один источник данных типа singleton и предоставляет доступ к его общему клиенту через интерфейсы
IClickHouseTcpClient и IClickHouseTcpOperations:
LoggerFactory,
при регистрации используется ILoggerFactory контейнера. serviceKey позволяет зарегистрировать несколько
независимых источников данных.
Выполнение запросов
Для команд, которые не возвращают строк, например DDL-команд и мутаций, используйтеExecuteAsync:
ExecuteAsync считывает и отбрасывает их. Для
INSERT INTO ... VALUES используйте InsertAsync или InsertRowsAsync, а SQL-оператор завершайте ключевым словом
VALUES, не указывая значения непосредственно в запросе.
Чтение данных
Выберите API для чтения в зависимости от того, в каком виде приложению нужны данные:Чтение скалярных значений
ExecuteScalarAsync возвращает значение из первого столбца первой строки как object:
NULL или запрос
не возвращает ни одной строки, в обоих случаях результатом будет null.
Чтение строк
QueryAsync потоково выдаёт каждую строку как отдельный массив object[], значения в котором расположены в порядке столбцов результата:
Чтение данных в объекты POCO
QueryAsync<T> сопоставляет столбцы с общедоступными свойствами, доступными для записи. При сопоставлении имён не учитываются регистр и
символы подчёркивания. Чтобы явно задать имя, используйте ClickHouseTcpColumn, а чтобы исключить свойство — ClickHouseTcpNotMapped.
Чтение данных столбцовыми блоками
StreamAsync возвращает результат в нативном столбцовом формате как последовательность блоков Block. Это самый быстрый способ чтения данных.
Обязательно завершите перебор или освободите перечислитель, чтобы связанное с ним соединение вернулось в пул.
Block.Column<T> предоставляет доступ к значениям в типе CLR, сформированном декодером. Если требуется преобразование, используйте Block.ReadAs<T> или
специализированный интерфейс, например IDateTimeColumn.
Вставка данных
Нативные вставки передают данные в виде столбцовых блоков в двоичном формате. SQL должен содержать операторINSERT INTO ... VALUES
без списка значений в самом запросе. Чтобы свести к минимуму обработку на стороне клиента, используйте типизированные столбцы; если данные в приложении уже представлены построчно,
используйте перегрузки для строк и объектов POCO.
Столбцовая вставка
InsertAsync принимает данные, уже сгруппированные по столбцам с заданными типами. Это самый быстрый способ вставки данных.
InsertAsync, если
вставка завершится до освобождения этого блока.
Вставка строк
InsertRowsAsync принимает строки в виде массивов object[]. Значения сопоставляются со столбцами из списка в SQL-запросе в порядке их следования:
Variant или Dynamic. Не изменяйте строки до завершения операции.
Вставка данных из POCO
Обобщённая перегрузкаInsertRowsAsync<T> сопоставляет столбцы целевой таблицы с общедоступными свойствами, доступными для чтения, по
тем же правилам именования и использования атрибутов, что и при чтении данных в POCO:
ClickHouseTcpNotMapped исключает из сопоставления свойства, используемые только приложением, например
ImportBatch.
Параметры SQL
Нативный клиент подставляет значения в плейсхолдеры{name:Type} нативного синтаксиса ClickHouse. Плейсхолдеры
@name в стиле ADO.NET он не преобразует.
ClickHouseTcpParameter.ClickHouseType. Для имён таблиц и столбцов используйте тип Identifier.
Если значение DateTime или DateTimeOffset обозначает конкретный момент времени, укажите часовой пояс, например
{timestamp:DateTime('UTC')}; в противном случае часовой пояс сеанса сервера может повлиять на интерпретацию этого значения.
Идентификатор запроса
Каждой операции соответствует идентификатор запроса, который используется в системных таблицах ClickHouse, журналах клиента и спанах трассировки. ЕслиQueryId имеет значение null или пуст, клиент генерирует новый GUID. Укажите его, если операцию необходимо
коррелировать с идентификатором приложения:
Ход выполнения запроса и метаданные
НастройтеClickHouseTcpQueryOptions.Callbacks, чтобы получать метаданные вперемежку с данными ответа:
OnLog, OnProfileEvents, OnTotals и OnExtremes, доступны только на время вызова и не должны использоваться после завершения
обратного вызова.
ClickHouse не отправляет пакеты о ходе выполнения запроса для строк, загружаемых при вставке. Используйте
OnBlockWritten, чтобы отслеживать блоки, отправленные клиентом; этот обратный вызов сообщает о ходе передачи, но не о том, что
сервер закоммитил вставку.
Отмена
Каждая операция принимаетCancellationToken:
Информация о сервере и проверки его работоспособности
GetServerInfoAsync возвращает идентификатор сервера, его версию, часовой пояс и сведения о протоколе, согласованном
при рукопожатии по нативному протоколу:
ProtocolRevision — ревизии, согласованной клиентом и
сервером. Поддержку возможностей SQL, таких как типы данных и функции, определяйте по Version. Метод использует существующее
соединение, если оно доступно, и открывает новое, если пул пуст.
Используйте PingAsync для проверки готовности по собственному протоколу:
Дополнительные примеры
Полные примеры, которые можно запустить и которые охватывают чтение данных, вставку, типы данных, сеансы, TLS, обсервабилити и обработку ошибок, см. в примерах использования нативного TCP в репозитории GitHub.Сеансы
Обычные операции клиента используют любое свободное соединение из пула, поэтому состояние, связанное с соединением, не изолировано и может не сохраняться между вызовами. Соединения из одного пула могут вести к разным серверам. Откройте сеанс, если для работы с временными таблицами, выполнения операторовSET или последовательности других операций требуется одно и то же соединение.
IClickHouseTcpSession предоставляет те же API для выполнения запросов и команд, вставки данных, проверки доступности и получения информации о сервере,
что и клиент. Сеанс не является потокобезопасным. Операции в нём выполняются последовательно: попытка начать новую операцию до завершения текущей
будет отклонена. При потоковой обработке результата сеанс остаётся занятым, пока результат не будет полностью перебран или
не будет освобождён его перечислитель.
Каждый сеанс занимает один слот MaxPoolSize на протяжении всего времени своего существования. Клиент может продолжать использовать другие
соединения из пула, но если в пуле всего одно соединение, другие операции клиента будут ожидать,
пока сеанс не будет освобождён или не истечёт время ожидания PoolTimeout.
Освободите сеанс до того, как освободите создавший его клиент. При освобождении сеанса закреплённое за ним
соединение закрывается, а не возвращается в пул. Благодаря этому последующие операции не унаследуют
временные таблицы или настройки сеанса. Сбой соединения или протокола, отмена операции либо не полностью обработанный
поток результатов могут сделать сеанс непригодным для использования; если IsOpen принимает значение false, откройте новый сеанс.
Рекомендации
Время жизни клиента и пул соединений
Создайте по одномуClickHouseTcpClient или ClickHouseTcpDataSource для каждой уникальной комбинации конечной точки и
конфигурации и используйте его в течение всего времени работы приложения. Клиент безопасен для использования из нескольких потоков и управляет
собственным пулом соединений. Если создавать клиент для каждой операции, каждый раз будет создаваться новый пул, а повторное использование
соединений станет невозможным.
В приложении с внедрением зависимостей один раз зарегистрируйте AddClickHouseTcpDataSource и внедряйте
IClickHouseTcpClient. Жизненным циклом клиента управляет контейнер зависимостей, поэтому компоненты, получающие клиент, не должны освобождать
внедрённый экземпляр. Если внедрение зависимостей не используется, освобождайте клиент при остановке приложения с помощью await using.
Каждое соединение по нативному протоколу выполняет только одну операцию за раз. Поэтому MaxPoolSize ограничивает и число открытых
соединений, и число параллельных операций; дополнительные вызовы ожидают свободного соединения не дольше PoolTimeout.
Выбирайте значение с учётом фактического параллелизма приложения, не превышая установленных на сервере
ограничений на соединения и запросы. Увеличение этого значения не ускорит отдельный запрос.
Учитывайте, что соединения из пула также используются в следующих случаях:
- При потоковой обработке результата соединение остаётся занятым, пока не будет освобождён перечислитель.
- Сеанс удерживает одно соединение на протяжении всего времени своего существования и выполняет только одну операцию за раз.
- Если обработка результата прервана, операция отменена во время выполнения или произошёл сбой протокола либо соединения, соединение закрывается, а не используется повторно.
ClickHouse.Driver.Tcp.Pool для диагностики исчерпания пула,
неожиданного закрытия соединений или частого повторного установления соединений.
Тайм-ауты и отмена
У TCP-клиента для разных этапов ожидания предусмотрены отдельные ограничения:
Получение соединения, при котором сначала нужно дождаться свободного слота в пуле, а затем установить новое соединение, может занять до
PoolTimeout + DialTimeout. Отсчёт ReadTimeout начинается заново при каждом чтении из транспорта, поэтому длительный запрос, в ходе которого
продолжают поступать сведения о ходе выполнения или данные, может выполняться дольше этого времени. Установите значение, достаточное для допустимых
периодов, когда сервер не передаёт данные; задавайте TimeSpan.Zero только в том случае, если длительность операции надёжно ограничена
другим тайм-аутом.
Если нужно ограничить время выполнения всей операции, используйте токен отмены:
Обработка даты и времени
Для временных меток предпочтительныDateTime('UTC') или DateTime64(S, 'UTC'), а в прикладном коде — DateTimeOffset или
DateTime со значением Utc для Kind. Так момент времени задаётся однозначно
и не зависит от часового пояса сервера или сеанса.
При записи значений DateTime TCP-клиент применяет следующие правила:
Значение
Unspecified, попадающее в пропущенный при переходе на летнее время интервал, отклоняется: ему не соответствует
ни один момент времени. Если при возврате на зимнее время показание часов повторяется, выбирается первый из двух моментов. Используйте DateTimeOffset, когда
выбор необходимо задать явно.
Для параметров SQL, обозначающих момент времени, указывайте часовой пояс в плейсхолдере:
DateTime и DateTime64 по умолчанию возвращают исходные числовые значения в типах uint или long.
Используйте Block.ReadAs<DateTimeOffset>, IDateTimeColumn.GetDateTimeOffset или соответствующее свойство POCO,
если удобнее работать с календарной датой и временем. Если важна каждая цифра, сохраняйте исходное числовое значение:
разрешение DateTimeOffset составляет 100 наносекунд, поэтому при чтении через него значений DateTime64 с масштабом 8 или 9
теряется точность на уровне долей тика.
Используйте DateOnly для Date и Date32. Для значений Time и Time64, которые могут быть
отрицательными или превышать 24 часа, используйте TimeSpan; TimeOnly подходит только тогда, когда значения столбца ограничены
временем суток.
Потоковая обработка и время жизни результатов
Для обработки с высокой пропускной способностью используйтеStreamAsync и типизированные столбцы. Это соответствует
столбцовой структуре ClickHouse и позволяет избежать создания массивов для каждой строки, упаковки значений и выделения памяти под POCO. Используйте QueryAsync<T>, когда
важнее получить модель приложения, владеющую своими данными, чем свести выделение памяти к минимуму, а нетипизированный
QueryAsync — только если схема неизвестна на этапе компиляции.
Блоки, возвращаемые StreamAsync, предоставляются без передачи владения. Блок, его столбцы, дочерние столбцы составных типов и
все спаны доступны только в течение текущей итерации цикла. Обрабатывайте их на месте или копируйте значения, которые
понадобятся после завершения итерации:
await foreach сам освободит перечислитель. Если нужна только часть
результата, ограничьте выборку в SQL с помощью LIMIT и выбирайте только необходимые столбцы. Досрочное прекращение перебора
отменяет получение оставшейся части ответа и не позволяет повторно использовать соединение.
Структура вставки и формирование батчей
Если данные уже организованы по столбцам, используйтеInsertAsync с типизированными столбцами: этот метод сводит к минимуму преобразования на стороне клиента. Для объектов POCO лучше подходит InsertRowsAsync<T>. Строки в виде нетипизированных object[] дают наибольшую гибкость, но требуют выделения памяти под массивы и упаковки значимых типов.
Передавайте достаточное количество строк за один вызов вставки вместо множества небольших вставок. В пределах одного вызова MaxRowsPerBlock разбивает данные на блоки нативного формата передачи. Значение по умолчанию — 50 000 строк — также ограничивает размер временных буферов столбцов при преобразовании строк и объектов POCO. Увеличение этого значения может повысить пропускную способность для строк с небольшим числом столбцов, но увеличит пиковое потребление памяти. Если задать null, вся вставка будет записана одним блоком, а все входные данные, организованные по строкам, будут преобразованы за один раз.
MaxSendBufferBytes отдельно ограничивает объём закодированных данных, которые накапливаются в буфере перед отправкой через сокет. Это мягкое ограничение проверяется между столбцами, поэтому один широкий столбец может его превысить.
Строки и объекты POCO преобразуются по одному блоку за раз. Поэтому недопустимое значение в одном из последующих блоков может обнаружиться уже после отправки предыдущих блоков. Если качество данных вызывает сомнения, перед вставкой проверьте допустимость NULL и типы CLR. Если возможна повторная отправка логического батча, задайте DeduplicationToken на основе данных.
Поддерживаемые типы данных
В таблицах ниже отдельно указаны тип, возвращаемый при декодированииIColumn<T>, и дополнительные типы,
доступные при преобразовании через Block.ReadAs<T>, сопоставлении с POCO через QueryAsync<T> или вставке. Проверить, поддерживается ли конкретное
сопоставление, можно с помощью того же механизма разрешения типов, который используется при этих операциях:
Nullable, Array, Tuple, Map и LowCardinality рекурсивно применяются к вложенным
типам.
Сопоставление типов: чтение из ClickHouse
Default .NET type — это тип T, доступный через Block.Column<T> и IColumn<T>. Типы, указанные в столбце
Also readable as, можно читать через Block.ReadAs<T> и свойства POCO.
Целочисленные типы
Типы с плавающей запятой
Десятичные типы
ClickHouseTcpDecimal хранит мантиссу как целое число произвольной разрядности и масштаб, что позволяет сохранять значения,
точность которых превышает возможности типа decimal.
Булевый тип
Строковые типы
Если данные могут не соответствовать кодировке UTF-8, используйте
IStringColumn.GetBytes(row) или считывайте их как byte[].
FixedString(N) сохраняет все N байтов, включая нулевые байты в конце.
Типы даты и времени
По умолчанию значения читаются как целые числа, чтобы при чтении по столбцам сохранялось их точное представление в передаваемых данных. При
преобразовании в календарные значения используется часовой пояс, указанный в типе, а если он не указан — часовой пояс сеанса. При чтении
Time или Time64 как TimeOnly генерируется исключение, если значение отрицательное или составляет не менее 24 часов. Для
работы с полным диапазоном значений ClickHouse используйте TimeSpan.
Типы Enum
IEnumColumn также позволяет получить объявленное соответствие меток их числовым значениям.
Другие скалярные типы
Составные типы
Кортежи могут содержать до семи элементов. Столбец
Nested не зависит от числа полей; его удобнее всего читать
через INestedColumn, который предоставляет доступ к отдельным столбцам с именами полей и общим смещениям строк без
выделения памяти под записи, упакованные в объекты. При заданном в ClickHouse по умолчанию параметре flatten_nested = 1 вложенные поля вместо этого поступают как
отдельные столбцы Array(T) с точкой в имени.
Типы Variant, Dynamic и JSON
Variant и Dynamic возвращают для каждой строки значение CLR выбранного типа или null. Их
столбцовые представления предоставляют поток дискриминаторов и по одному дочернему столбцу с заданным типом для каждого типа, встречающегося во время выполнения. Это позволяет избежать
упаковки значений при обработке данных по столбцам.
TCP-клиент считывает JSON с помощью сериализации ClickHouse в формате String. По умолчанию клиент включает
output_format_native_write_json_as_string = 1; если отключить этот параметр, чтение JSON
не поддерживается. ClickHouse разбирает и нормализует JSON, поэтому возвращаемый текст может отличаться от вставленного
порядком ключей, пробелами и форматированием чисел.
Геометрические типы
Geometry представляется интерфейсом IVariantColumn, объединяющим шесть геометрических типов.
Тип QBit
TCP-клиент поддерживает форму
QBit(T, N) с двумя аргументами, без параметра stride. Структура с тремя аргументами
и параметром stride не поддерживается.
Типы AggregateFunction
Столбец типа
AggregateFunction содержит промежуточное состояние, зависящее от функции. Получите окончательный результат на
сервере, например с помощью sumMerge(column), и считайте полученное значение.
Сопоставление типов: запись в ClickHouse
Каждая запись указывает тип CLR одной строки вIColumn, переданном в InsertAsync. Соответствие типов
точное: TCP-клиент не выполняет неявных преобразований по аналогии с Convert.
Целочисленные типы
Типы с плавающей запятой
При записи в формате
BFloat16 каждое значение float усекается до 16-битного представления с плавающей запятой (brain floating point).
Десятичные типы
При записи генерируется исключение
OverflowException, если количество цифр мантиссы после масштабирования превышает заданную точность.
Булевый тип
Строковые типы
FixedString(N) намеренно не принимает значения типа string: их необходимо явно закодировать и дополнить до нужной длины, чтобы
двоичное представление каждого значения было однозначным.
Типы даты и времени
Целочисленные значения без преобразования задаются в единицах измерения, указанных в таблице для чтения.
DateTimeOffset сохраняет момент времени.
Для DateTime учитывается значение Kind: значение Unspecified интерпретируется как местное время в часовом поясе
столбца, а если для столбца часовой пояс не задан — в часовом поясе сеанса.
Типы Enum
Неизвестное имя элемента перечисления отклоняется до отправки данных.
Другие скалярные типы
Составные типы
Допустимые структуры определяются рекурсивно:Array(Nullable(DateTime)) принимает DateTime?[] для каждой
строки, а Map(String, UInt32) — KeyValuePair<string, uint>[].
При прямой записи
Nested используется плотное представление столбцов, полученное при предыдущем чтении. Для вставок,
формируемых приложением, используйте представление flatten_nested = 1 по умолчанию и записывайте каждое поле Array(T) с именем, содержащим точку,
в отдельный столбец.
Типы Variant, Dynamic и JSON
Для
Variant тип значения во время выполнения должен однозначно соответствовать типу CLR по умолчанию для одного из вариантов. Дополнительные
преобразования, например запись DateTime в вариант DateTime, внутри Variant не применяются;
вместо них используйте исходный тип по умолчанию для соответствующего варианта. Dynamic поддерживает скалярные значения,
а также значения массивов, отображений и кортежей, в том числе вложенные, если их типы поддерживаются.
Геометрические типы
Если столбец
Geometry создаётся приложением, только Point и MultiPolygon имеют уникальные структуры CLR.
У Ring и LineString структура совпадает, как и у Polygon и MultiLineString, поэтому клиент не может
определить, какой из типов представляет значение object. Декодированный столбец Geometry сохраняет
дискриминаторы, поэтому его можно повторно вставить без такой неоднозначности.
Тип QBit
Типы AggregateFunction
Сжатие
По умолчанию клиент использует сжатие LZ4 для записываемых блоков; ClickHouse также по умолчанию сжимает блоки ответа с помощью LZ4. Сжатие применяется к блокам результатов и блокам, передаваемым при вставке, а текст запроса, сведения о ходе его выполнения, исключения и другие пакеты протокола передаются без сжатия в обычном формате передачи данных. Чтобы выбрать кодек для клиента, укажите параметрCompression в строке соединения:
IClickHouseCompressor:
Compressor = null, чтобы отключить сжатие. Пользовательский компрессор должен поддерживать фрейминг блоков нативного формата;
компрессоры, поддерживающие только тела HTTP-сообщений, не принимаются при создании клиента.
Выбор кодека для ответа
Compressor определяет, как сжимаются блоки, записываемые клиентом. Пакет Query нативного протокола
запрашивает у сервера сжатие, но не указывает кодек. Поэтому ClickHouse выбирает кодек для ответа
согласно настройке network_compression_method. По умолчанию сервер использует LZ4.
При необходимости задавайте кодек для ответа отдельно для каждой операции:
Обработка ошибок
Ошибки ClickHouse или соединения по собственному протоколу представлены исключениями, унаследованными отClickHouseTcpException,
который, в свою очередь, наследуется от DbException:
ClickHouseTcpServerException содержит RawCode — точный числовой код, присланный сервером,
и Code — соответствующее значение ClickHouseErrorCode, если для этого кода есть имя в драйвере. Также в нём доступны
имя исключения сервера в Name, трассировка стека в ServerStackTrace и вложенные исключения сервера в
InnerException.
ClickHouseErrorCode, имеют значение Code == ClickHouseErrorCode.Unknown; проверяйте
RawCode, поскольку перечисление может содержать не все коды ошибок ClickHouse.
Ошибки проверки аргументов и жизненного цикла объектов по-прежнему представлены стандартными для .NET типами исключений.
При отмене операции возникает OperationCanceledException. При DialTimeout и ReadTimeout возникает
ClickHouseTcpConnectionException с вложенным исключением TimeoutException, а соединение удаляется из пула.
При PoolTimeout возникает обычное исключение TimeoutException, а не ClickHouseTcpException: сбоя
соединения не было. Чтобы устранить проблему, сократите число параллельных операций, увеличьте пул или завершите перебор результатов.
Повторное выполнение операций
Если во время вставки произошёл сбой соединения или истёк тайм-аут, результат операции остаётся неизвестным: сервер мог записать строки до того, как клиент потерял соединение и не получил ответ. Перед повторной попыткой задайте для логического батча постоянное значениеDeduplicationToken:
Логирование и диагностика
TCP-клиент интегрируется сMicrosoft.Extensions.Logging. Логирование необязательно: без
LoggerFactory клиент не создаёт логгеры и не форматирует сообщения лога.
ILoggerFactory из контейнера,
если фабрика логирования уже не указана в переданных параметрах.
Категории логирования
Настройте категории с помощью стандартных параметров логирования .NET:
Debug и содержит не более StatementMaxLength символов
SQL. По умолчанию — пять символов. Установите значение не выше нуля, чтобы не записывать текст оператора в журналы,
а увеличивайте его только после проверки параметров и литералов на наличие конфиденциальных данных.
Сообщения лога сервера
Интеграция логирования передаёт сведения о работе клиента. Пакеты журнала запросов самого ClickHouse передаются отдельно вClickHouseTcpQueryCallbacks.OnLog. Чтобы включить их, используйте
настройку сервера send_logs_level:
OpenTelemetry
TCP-клиент создаёт спаны распределённой трассировки с помощью APISystem.Diagnostics.Activity в .NET.
Подпишитесь на источник активности TCP-клиента с помощью провайдера трассировки OpenTelemetry:
ClickHouse.Driver.Tcp. Оно отличается от имени источника HTTP-клиента, поэтому
события для каждого из этих транспортов можно собирать независимо. Если ни один обработчик не подписан, операции не
создают событий.
Спаны и атрибуты
Клиент создает спаны для SQL-операций, проверок доступности и новых соединений. Спан SQL-операции получает имя по первому ключевому слову оператора, напримерSELECT или INSERT; если его не удается
распознать, используется query. Спан connect охватывает установление соединения через сокет, согласование TLS и
рукопожатие по нативному протоколу. Спаны SQL-операций также включают время ожидания соединения из пула.
Счетчики присутствуют, только если у сервера или клиента есть значимые значения для передачи. Например,
при вставке с загрузкой блоков указывается количество строк, отправленных клиентом, но данные о прочитанных строках от
сервера не поступают. Спаны неудачных операций также содержат событие
exception с типом исключения, сообщением и трассировкой
стека.
Текст SQL-запросов и конфиденциальные данные
По умолчанию текст SQL-запросов не включается в спаны. Включите его передачу явно и задайте подходящий лимит:StatementMaxLength ограничивает длину атрибута db.query.text и SQL-текста в отладочных журналах. Если значение равно нулю
или меньше, SQL-текст не включается ни туда, ни туда. Также проверяйте экспортируемые сообщения об исключениях и трассировки стека:
ошибки сервера могут содержать подробности запросов.
Передача контекста трассировки
ЕслиActivity.Current использует формат идентификаторов W3C, клиент записывает идентификатор трассировки, идентификатор спана, флаги
и состояние трассировки в пакет Query нативного протокола. После этого ClickHouse может создавать серверные спаны в той же
распределённой трассировке. Сбор серверных спанов и сэмплирование настраиваются на стороне ClickHouse; например,
вероятность сэмплирования можно задать для каждого запроса:
system.query_log и, если ведение журнала спанов включено, с таблицей ClickHouse system.opentelemetry_span_log.
Ограничения
TCP-клиент пока экспериментальный и поддерживает не все возможности HTTP-клиента.Возможности, доступные только через HTTP
TCP API не является провайдером ADO.NET и не может использоваться с ORM. Он также не поддерживает ввод и вывод в форматах CSV, JSONEachRow, Parquet или в виде сырого потока; аутентификацию по схеме bearer и пользовательские HTTP-заголовки; пользовательские правила определения типов параметров, форматирования и преобразования при чтении; указание базы данных или роли для каждого запроса. Если приложению нужна хотя бы одна из этих возможностей, используйте HTTP-клиент.Параметры SQL
Поддерживаются только плейсхолдеры ClickHouse формата{name:Type}; TCP-клиент не преобразует
плейсхолдеры ADO.NET вида @name. В версиях ClickHouse с 25.8 по 26.6 имена параметров, совпадающие
с именами настроек сервера, например limit или offset, могут быть приняты за настройки и отклонены. Если необходимо поддерживать
эти версии, переименуйте такие параметры, например в row_limit.
Поддержка типов данных
Полное соответствие типов описано в разделе Поддерживаемые типы данных. У текущего нативного кодека есть следующие ограничения:- Tuple может содержать не более семи элементов.
- Промежуточные состояния
AggregateFunction(function, ...)не поддерживаются. Завершайте их обработку на сервере, например с помощьюsumMerge(column), и считывайте готовый результат. - Поддерживается только структура
QBit(T, N)с двумя аргументами, без разбиения измерений на группы. - Для
JSONиспользуется сериализация ClickHouse в тип String, поэтому необходима настройкаoutput_format_native_write_json_as_string = 1, которую клиент запрашивает по умолчанию. - При вставке данных, сформированных приложением, для
Nested(...)недоступно построчное представление, еслиflatten_nested = 0. Вместо него используйте развёрнутые столбцыArray(T)с именами через точку, применяемые по умолчанию. - Для столбца
Geometry, сформированного приложением, нельзя автоматически определить тип среди вариантов с одинаковой структурой CLR, напримерRingиLineString. Вставляйте данные с конкретным геометрическим типом либо повторно вставляйте декодированный столбецGeometry, сохранивший свои дискриминаторы.
Автоматические повторные попытки
Клиент не повторяет операции автоматически после сбоя. Повторяйте только те операции, которые можно безопасно выполнить ещё раз. Если результат вставки неизвестен, перед повторной попыткой задайте для неё неизменныйDeduplicationToken.
Подробнее см. в разделе «Повторные попытки выполнения операций».