Перейти к основному содержимому
Перейти к основному содержимому

ClickHouse JS

Официальный JS клиент для подключения к ClickHouse. Клиент написан на TypeScript и предоставляет типизацию для публичного API клиента.

Он не имеет зависимостей, оптимизирован для максимальной производительности и протестирован с различными версиями и конфигурациями ClickHouse (одиночный узел на месте, кластер на месте и ClickHouse Cloud).

Доступны две разные версии клиента для разных сред:

  • @clickhouse/client - только для Node.js
  • @clickhouse/client-web - браузеры (Chrome/Firefox), Cloudflare workers

При использовании TypeScript убедитесь, что это как минимум версия 4.5, которая включает синтаксис импорта и экспорта встраивания.

Исходный код клиента доступен в репозитории ClickHouse-JS на GitHub.

Требования к среде (node.js)

Node.js должен быть доступен в среде для работы клиента. Клиент совместим со всеми поддерживаемыми версиями Node.js.

Как только версия Node.js приближается к окончанию жизненного цикла, клиент прекращает поддержку этой версии, считая её устаревшей и небезопасной.

Поддерживаемые текущие версии Node.js:

Версия Node.jsПоддерживается?
22.x
20.x
18.x
16.xПрилагаем усилия

Требования к среде (web)

Веб-версия клиента официально тестируется с последними браузерами Chrome/Firefox и может использоваться как зависимость в, например, приложениях React/Vue/Angular или Cloudflare workers.

Установка

Чтобы установить последнюю стабильную версию клиента Node.js, выполните:

npm i @clickhouse/client

Установка веб-версии:

npm i @clickhouse/client-web

Совместимость с ClickHouse

Версия клиентаClickHouse
1.12.024.8+

Скорее всего, клиент будет работать и с более старыми версиями; однако это поддерживаемая версия, и гарантий нет. Если у вас версия ClickHouse старше 23.3, пожалуйста, ознакомьтесь с политикой безопасности ClickHouse и подумайте о выполнении обновления.

Примеры

Мы стремимся рассмотреть различные сценарии использования клиента в примерах в репозитории клиента.

Обзор доступен в README примеров.

Если что-то неясно или отсутствует в примерах или в следующей документации, не стесняйтесь связаться с нами.

API клиента

Большинство примеров должны быть совместимы как с Node.js, так и с веб-версией клиента, если не указано иное.

Создание экземпляра клиента

Вы можете создать сколько угодно экземпляров клиента с помощью фабрики createClient:

import { createClient } from '@clickhouse/client' // or '@clickhouse/client-web'

const client = createClient({
  /* configuration */
})

Если ваша среда не поддерживает модули ESM, вы можете использовать синтаксис CJS вместо этого:

const { createClient } = require('@clickhouse/client');

const client = createClient({
  /* configuration */
})

Экземпляр клиента может быть предварительно настроен при его создании.

Конфигурация

При создании экземпляра клиента можно настроить следующие параметры подключения:

ПараметрОписаниеЗначение по умолчаниюСм. Также
url?: stringURL экземпляра ClickHouse.http://localhost:8123Документация по конфигурации URL
pathname?: stringНеобязательный путь, который будет добавлен к URL ClickHouse после его парсинга клиентом.''Прокси с путём документация
request_timeout?: numberТаймаут запроса в миллисекундах.30_000-
compression?: { **response**?: boolean; **request**?: boolean }Включить сжатие.-Документация по сжатию
username?: stringИмя пользователя, от имени которого отправляются запросы.default-
password?: stringПароль пользователя.''-
application?: stringИмя приложения, использующего клиент Node.js.clickhouse-js-
database?: stringИмя базы данных, которую нужно использовать.default-
clickhouse_settings?: ClickHouseSettingsНастройки ClickHouse, применяемые ко всем запросам.{}-
log?: { **LoggerClass**?: Logger, **level**?: ClickHouseLogLevel }Настройки внутренних логов клиента.-Документация по логированию
session_id?: stringНеобязательный идентификатор сессии ClickHouse, который отправляется с каждым запросом.--
keep_alive?: { **enabled**?: boolean }Включен по умолчанию в обеих версиях Node.js и Web.--
http_headers?: Record<string, string>Дополнительные HTTP заголовки для исходящих запросов ClickHouse.-Обратный прокси с аутентификацией документация
roles?: string | string[]Имена ролей ClickHouse, которые необходимо прикрепить к исходящим запросам.-Использование ролей с HTTP-интерфейсом

Параметры конфигурации, специфичные для Node.js

ПараметрОписаниеЗначение по умолчаниюСм. Также
max_open_connections?: numberМаксимальное количество открытых соединений для каждого хоста.10-
tls?: { **ca_cert**: Buffer, **cert**?: Buffer, **key**?: Buffer }Настройка сертификатов TLS.-Документация по TLS
keep_alive?: { **enabled**?: boolean, **idle_socket_ttl**?: number }--Документация по настройке Keep Alive
http_agent?: http.Agent | https.Agent
Experimental feature. Learn more.
Пользовательский HTTP-агент для клиента.-Документация по HTTP-агенту
set_basic_auth_header?: boolean
Experimental feature. Learn more.
Установить заголовок Authorization с учетными данными базовой аутентификации.trueиспользование этой настройки в документации по HTTP-агенту

Конфигурация URL

к сведению

Конфигурация URL всегда перезаписывает жестко закодированные значения, и в этом случае будет записано предупреждение.

Возможно настроить большинство параметров экземпляра клиента с помощью URL. Формат URL: http[s]://[username:password@]hostname:port[/database][?param1=value1&param2=value2]. В почти каждом случае имя конкретного параметра отражает его путь в интерфейсе параметров конфигурации, с несколькими исключениями. Поддерживаются следующие параметры:

ПараметрТип
pathnameпроизвольная строка.
application_idпроизвольная строка.
session_idпроизвольная строка.
request_timeoutнеотрицательное число.
max_open_connectionsнеотрицательное число, больше нуля.
compression_requestбулево. См. ниже (1)
compression_responseбулево.
log_levelдопустимые значения: OFF, TRACE, DEBUG, INFO, WARN, ERROR.
keep_alive_enabledбулево.
clickhouse_setting_* или ch_*см. ниже (2)
http_header_*см. ниже (3)
(только для Node.js) keep_alive_idle_socket_ttlнеотрицательное число.
  • (1) Для булевых значений допустимыми значениями будут true/1 и false/0.
  • (2) Любой параметр, начинающийся с clickhouse_setting_ или ch_, будет иметь этот префикс удален, а остальная часть добавлена в настройки клиента clickhouse_settings. Например, ?ch_async_insert=1&ch_wait_for_async_insert=1 будет равносильно:
createClient({
  clickhouse_settings: {
    async_insert: 1,
    wait_for_async_insert: 1,
  },
})

Примечание: булевые значения для clickhouse_settings должны передаваться как 1/0 в URL.

  • (3) Аналогично (2), но для конфигурации http_header. Например, ?http_header_x-clickhouse-auth=foobar будет эквивалентно:
createClient({
  http_headers: {
    'x-clickhouse-auth': 'foobar',
  },
})

Подключение

Соберите детали подключения

Чтобы подключиться к ClickHouse с помощью HTTP(S), вам необходима следующая информация:

  • ХОСТ и ПОРТ: как правило, порт 8443 при использовании TLS или 8123 при отсутствии TLS.

  • ИМЯ БАЗЫ ДАННЫХ: по умолчанию существует база данных с именем default, используйте имя базы данных, к которой вы хотите подключиться.

  • ИМЯ ПОЛЬЗОВАТЕЛЯ и ПАРОЛЬ: по умолчанию имя пользователя default. Используйте имя пользователя, подходящее для вашего случая.

Данные для вашего сервиса ClickHouse Cloud доступны в консоли ClickHouse Cloud. Выберите сервис, к которому вы хотите подключиться, и нажмите Подключиться:

Кнопка подключения к сервису ClickHouse Cloud

Выберите HTTPS, и данные будут доступны в примере команды curl.

Детали подключения ClickHouse Cloud по HTTPS

Если вы используете самоуправляемый ClickHouse, детали подключения устанавливаются вашим администратором ClickHouse.

Обзор подключения

Клиент реализует подключение через HTTP(s) протокол. Поддержка RowBinary в работе, см. связанную проблему.

Следующий пример демонстрирует, как установить соединение с ClickHouse Cloud. Предполагается, что значения url (включая протокол и порт) и password указаны через переменные окружения, и используется пользователь default.

Пример: Создание экземпляра клиента Node.js с использованием переменных окружения для конфигурации.

import { createClient } from '@clickhouse/client'

const client = createClient({
  url: process.env.CLICKHOUSE_HOST ?? 'http://localhost:8123',
  username: process.env.CLICKHOUSE_USER ?? 'default',
  password: process.env.CLICKHOUSE_PASSWORD ?? '',
})

Репозиторий клиента содержит множество примеров, использующих переменные окружения, таких как создание таблицы в ClickHouse Cloud, использование асинхронных вставок и множество других.

Пул подключений (только Node.js)

Чтобы избежать накладных расходов на установление соединения при каждом запросе, клиент создает пул соединений с ClickHouse для повторного использования, используя механизм Keep-Alive. По умолчанию Keep-Alive включен, а размер пула соединений установлен на 10, однако вы можете изменить его с помощью параметра конфигурации max_open_connections.

Нет гарантии, что одно и то же соединение в пуле будет использоваться для последующих запросов, если пользователь не установит max_open_connections: 1. Это редко необходимо, но может потребоваться в случаях, когда пользователи используют временные таблицы.

См. также: Конфигурация Keep-Alive.

Идентификатор запроса

Каждый метод, который отправляет запрос или оператор (command, exec, insert, select), будет предоставлять query_id в результате. Этот уникальный идентификатор назначается клиентом для каждого запроса и может быть полезным для извлечения данных из system.query_log, если он включен в конфигурации сервера, или для отмены долгих запросов (см. пример). Если это необходимо, пользователь может переопределить query_id в параметрах методов command/query/exec/insert.

подсказка

Если вы переопределяете параметр query_id, вы должны гарантировать его уникальность для каждого вызова. Случайный UUID - хороший выбор.

Базовые параметры для всех методов клиента

Существуют несколько параметров, которые могут быть применены ко всем методам клиента (query/command/insert/exec).

interface BaseQueryParams {
  // ClickHouse settings that can be applied on query level.
  clickhouse_settings?: ClickHouseSettings
  // Parameters for query binding.
  query_params?: Record<string, unknown>
  // AbortSignal instance to cancel a query in progress.
  abort_signal?: AbortSignal
  // query_id override; if not specified, a random identifier will be generated automatically.
  query_id?: string
  // session_id override; if not specified, the session id will be taken from the client configuration.
  session_id?: string
  // credentials override; if not specified, the client's credentials will be used.
  auth?: { username: string, password: string }
  // A specific list of roles to use for this query. Overrides the roles set in the client configuration.
  role?: string | Array<string>
}

Метод запроса

Этот метод используется для большинства операторов, которые могут иметь ответ, таких как SELECT, или для отправки DDL, таких как CREATE TABLE, и должен ожидаться. Ожидается, что возвращаемый набор результатов будет использован в приложении.

примечание

Существует специальный метод insert для вставки данных и command для DDL.

interface QueryParams extends BaseQueryParams {
  // Query to execute that might return some data.
  query: string
  // Format of the resulting dataset. Default: JSON.
  format?: DataFormat
}

interface ClickHouseClient {
  query(params: QueryParams): Promise<ResultSet>
}

См. также: Базовые параметры для всех методов клиента.

подсказка

Не указывайте оператор FORMAT в query, используйте параметр format вместо этого.

Набор результатов и абстракции строк

ResultSet предоставляет несколько удобных методов для обработки данных в вашем приложении.

Реализация ResultSet в Node.js использует Stream.Readable под капотом, тогда как веб-версия использует Web API ReadableStream.

Вы можете использовать ResultSet, вызывая либо text, либо json методы на ResultSet и загружать весь набор строк, возвращаемых запросом, в память.

Вы должны начинать использовать ResultSet как можно скорее, поскольку он держит поток ответа открытым и, следовательно, поддерживает фоновые соединения занятыми. Клиент не буферизует входящие данные, чтобы избежать потенциального чрезмерного использования памяти приложением.

В качестве альтернативы, если это слишком велико, чтобы поместиться в память сразу, вы можете вызвать метод stream и обрабатывать данные в режиме потоковой передачи. Каждый из частей ответа будет преобразован в относительно небольшие массивы строк вместо (размер этого массива зависит от размера конкретной части, которую клиент получает от сервера, так как она может варьироваться, и размера отдельной строки), по одной части за раз.

Пожалуйста, ознакомьтесь со списком поддерживаемых форматов данных, чтобы определить, какой формат лучше всего подходит для потоковой передачи в вашем случае. Например, если вы хотите передавать объекты JSON, вы можете выбрать JSONEachRow, и каждая строка будет разобрана как JS объект, или, возможно, более компактный формат JSONCompactColumns, который будет приводить к тому, что каждая строка станет компактным массивом значений. См. также: поточные файлы.

к сведению

Если ResultSet или его поток не полностью использованы, он будет уничтожен после периода бездействия, равного request_timeout.

interface BaseResultSet<Stream> {
  // See "Query ID" section above
  query_id: string

  // Consume the entire stream and get the contents as a string
  // Can be used with any DataFormat
  // Should be called only once
  text(): Promise<string>

  // Consume the entire stream and parse the contents as a JS object
  // Can be used only with JSON formats
  // Should be called only once
  json<T>(): Promise<T>

  // Returns a readable stream for responses that can be streamed
  // Every iteration over the stream provides an array of Row[] in the selected DataFormat
  // Should be called only once
  stream(): Stream
}

interface Row {
  // Get the content of the row as a plain string
  text: string

  // Parse the content of the row as a JS object
  json<T>(): T
}

Пример: (Node.js/Web) Запрос с результатом в формате JSONEachRow, потребляющий весь поток и разбирая содержимое как JS объекты. Исходный код.

const resultSet = await client.query({
  query: 'SELECT * FROM my_table',
  format: 'JSONEachRow',
})
const dataset = await resultSet.json() // or `row.text` to avoid parsing JSON

Пример: (только Node.js) Результат запроса в формате JSONEachRow, использующий классический подход on('data'). Это взаимозаменяемо с синтаксисом for await const. Исходный код.

const rows = await client.query({
  query: 'SELECT number FROM system.numbers_mt LIMIT 5',
  format: 'JSONEachRow', // or JSONCompactEachRow, JSONStringsEachRow, etc.
})
const stream = rows.stream()
stream.on('data', (rows: Row[]) => {
  rows.forEach((row: Row) => {
    console.log(row.json()) // or `row.text` to avoid parsing JSON
  })
})
await new Promise((resolve, reject) => {
  stream.on('end', () => {
    console.log('Completed!')
    resolve(0)
  })
  stream.on('error', reject)
})

Пример: (только Node.js) Результат запроса в формате CSV, использующий классический подход on('data'). Это взаимозаменяемо с синтаксисом for await const. Исходный код

const resultSet = await client.query({
  query: 'SELECT number FROM system.numbers_mt LIMIT 5',
  format: 'CSV', // or TabSeparated, CustomSeparated, etc.
})
const stream = resultSet.stream()
stream.on('data', (rows: Row[]) => {
  rows.forEach((row: Row) => {
    console.log(row.text)
  })
})
await new Promise((resolve, reject) => {
  stream.on('end', () => {
    console.log('Completed!')
    resolve(0)
  })
  stream.on('error', reject)
})

Пример: (только Node.js) Результат запроса как JS объекты в формате JSONEachRow, потребляемый с помощью синтаксиса for await const. Это взаимозаменяемо с классическим подходом on('data'). Исходный код.

const resultSet = await client.query({
  query: 'SELECT number FROM system.numbers LIMIT 10',
  format: 'JSONEachRow', // or JSONCompactEachRow, JSONStringsEachRow, etc.
})
for await (const rows of resultSet.stream()) {
  rows.forEach(row => {
    console.log(row.json())
  })
}
примечание

Синтаксис for await const требует немного меньше кода, чем подход on('data'), но это может негативно повлиять на производительность. Смотрите эту проблему в репозитории Node.js для получения дополнительной информации.

Пример: (только Web) Итерация по ReadableStream объектов.

const resultSet = await client.query({
  query: 'SELECT * FROM system.numbers LIMIT 10',
  format: 'JSONEachRow'
})

const reader = resultSet.stream().getReader()
while (true) {
  const { done, value: rows } = await reader.read()
  if (done) { break }
  rows.forEach(row => {
    console.log(row.json())
  })
}

Метод вставки

Это основной метод для вставки данных.

export interface InsertResult {
  query_id: string
  executed: boolean
}

interface ClickHouseClient {
  insert(params: InsertParams): Promise<InsertResult>
}

Возвращаемый тип минимален, так как мы не ожидаем, что сервер вернет какие-либо данные, и немедленно очищаем поток ответа.

Если пустой массив был передан в метод вставки, оператор вставки не будет отправлен на сервер; вместо этого метод сразу разрешится с { query_id: '...', executed: false }. Если query_id не был предоставлен в параметрах метода в этом случае, он будет пустой строкой в результате, так как возврат случайного UUID, сгенерированного клиентом, может вызвать путаницу, поскольку запрос с таким query_id не будет существовать в таблице system.query_log.

Если оператор вставки был отправлен на сервер, флаг executed будет равен true.

Метод вставки и потоковая передача в Node.js

Он может работать либо с Stream.Readable, либо с обычным Array<T>, в зависимости от формата данных, указанного в методе insert. См. также этот раздел о файловой потоковой передаче.

Метод вставки должен ожидаться; однако возможно указать вводный поток и дождаться операции insert позже, только когда поток завершится (что также разрешит промис insert). Это может быть полезно для обработчиков событий и подобных сценариев, но обработка ошибок может быть нетривиальной с множеством нестандартных случаев на стороне клиента. Вместо этого рассмотрите возможность использования асинхронных вставок, как показано в этом примере.

подсказка

Если у вас есть собственный оператор INSERT, который сложно смоделировать с помощью этого метода, рассмотрите возможность использования метода command.

Вы можете посмотреть, как он используется в примерах INSERT INTO ... VALUES или INSERT INTO ... SELECT.

interface InsertParams<T> extends BaseQueryParams {
  // Table name to insert the data into
  table: string
  // A dataset to insert.
  values: ReadonlyArray<T> | Stream.Readable
  // Format of the dataset to insert.
  format?: DataFormat
  // Allows to specify which columns the data will be inserted into.
  // - An array such as `['a', 'b']` will generate: `INSERT INTO table (a, b) FORMAT DataFormat`
  // - An object such as `{ except: ['a', 'b'] }` will generate: `INSERT INTO table (* EXCEPT (a, b)) FORMAT DataFormat`
  // By default, the data is inserted into all columns of the table,
  // and the generated statement will be: `INSERT INTO table FORMAT DataFormat`.
  columns?: NonEmptyArray<string> | { except: NonEmptyArray<string> }
}

См. также: Базовые параметры для всех методов клиента.

к сведению

Запрос, отмененный с помощью abort_signal, не гарантирует, что вставка данных не произошла, поскольку сервер мог получить часть передаваемых данных до отмены.

Пример: (Node.js/Web) Вставить массив значений. Исходный код.

await client.insert({
  table: 'my_table',
  // structure should match the desired format, JSONEachRow in this example
  values: [
    { id: 42, name: 'foo' },
    { id: 42, name: 'bar' },
  ],
  format: 'JSONEachRow',
})

Пример: (только Node.js) Вставка потока из CSV файла. Исходный код. См. также: поточная передача файлов.

await client.insert({
  table: 'my_table',
  values: fs.createReadStream('./path/to/a/file.csv'),
  format: 'CSV',
})

Пример: Исключение определенных столбцов из оператора вставки.

С учетом такого определения таблицы:

CREATE OR REPLACE TABLE mytable
(id UInt32, message String)
ENGINE MergeTree()
ORDER BY (id)

Вставить только определенный столбец:

// Generated statement: INSERT INTO mytable (message) FORMAT JSONEachRow
await client.insert({
  table: 'mytable',
  values: [{ message: 'foo' }],
  format: 'JSONEachRow',
  // `id` column value for this row will be zero (default for UInt32)
  columns: ['message'],
})

Исключите определенные столбцы:

// Generated statement: INSERT INTO mytable (* EXCEPT (message)) FORMAT JSONEachRow
await client.insert({
  table: tableName,
  values: [{ id: 144 }],
  format: 'JSONEachRow',
  // `message` column value for this row will be an empty string
  columns: {
    except: ['message'],
  },
})

Смотрите исходный код для получения дополнительных деталей.

Пример: Вставить в базу данных, отличную от той, что указана экземпляру клиента. Исходный код.

await client.insert({
  table: 'mydb.mytable', // Fully qualified name including the database
  values: [{ id: 42, message: 'foo' }],
  format: 'JSONEachRow',
})

Ограничения веб-версии

В настоящее время вставки в @clickhouse/client-web работают только с Array<T> и JSON* форматами. Вставка потоков еще не поддерживается в веб-версии из-за плохой совместимости браузеров.

Соответственно, интерфейс InsertParams для веб-версии выглядит немного иначе, чем версия для Node.js, так как values ограничены только типом ReadonlyArray<T>:

interface InsertParams<T> extends BaseQueryParams {
  // Table name to insert the data into
  table: string
  // A dataset to insert.
  values: ReadonlyArray<T>
  // Format of the dataset to insert.
  format?: DataFormat
  // Allows to specify which columns the data will be inserted into.
  // - An array such as `['a', 'b']` will generate: `INSERT INTO table (a, b) FORMAT DataFormat`
  // - An object such as `{ except: ['a', 'b'] }` will generate: `INSERT INTO table (* EXCEPT (a, b)) FORMAT DataFormat`
  // By default, the data is inserted into all columns of the table,
  // and the generated statement will be: `INSERT INTO table FORMAT DataFormat`.
  columns?: NonEmptyArray<string> | { except: NonEmptyArray<string> }
}

Это может измениться в будущем. См. также: Базовые параметры для всех методов клиента.

Метод команд

Он может использоваться для операторов, не имеющих вывода, когда оператор формата не применим, или когда вы вообще не интересуетесь ответом. Примером такого оператора может быть CREATE TABLE или ALTER TABLE.

Должен быть ожидаем.

Поток ответа немедленно уничтожается, что означает, что подлежащий сокет освобождается.

interface CommandParams extends BaseQueryParams {
  // Statement to execute.
  query: string
}

interface CommandResult {
  query_id: string
}

interface ClickHouseClient {
  command(params: CommandParams): Promise<CommandResult>
}

См. также: Базовые параметры для всех методов клиента.

Пример: (Node.js/Web) Создание таблицы в ClickHouse Cloud. Исходный код.

await client.command({
  query: `
    CREATE TABLE IF NOT EXISTS my_cloud_table
    (id UInt64, name String)
    ORDER BY (id)
  `,
  // Recommended for cluster usage to avoid situations where a query processing error occurred after the response code, 
  // and HTTP headers were already sent to the client.
  // See https://clickhouse.com/docs/interfaces/http/#response-buffering
  clickhouse_settings: {
    wait_end_of_query: 1,
  },
})

Пример: (Node.js/Web) Создание таблицы в самообслуживаемом экземпляре ClickHouse. Исходный код.

await client.command({
  query: `
    CREATE TABLE IF NOT EXISTS my_table
    (id UInt64, name String)
    ENGINE MergeTree()
    ORDER BY (id)
  `,
})

Пример: (Node.js/Web) INSERT FROM SELECT

await client.command({
  query: `INSERT INTO my_table SELECT '42'`,
})
к сведению

Запрос, отмененный с помощью abort_signal, не гарантирует, что оператор не был выполнен сервером.

Метод exec

Если у вас есть собственный запрос, который не подходит для query/insert, и вас интересует результат, вы можете использовать exec как альтернативу command.

exec возвращает читаемый поток, который ДОЛЖЕН быть использован или уничтожен на стороне приложения.

interface ExecParams extends BaseQueryParams {
  // Statement to execute.
  query: string
}

interface ClickHouseClient {
  exec(params: ExecParams): Promise<QueryResult>
}

См. также: Базовые параметры для всех методов клиента.

Тип возвращаемого потока отличается в версиях Node.js и Web.

Node.js:

export interface QueryResult {
  stream: Stream.Readable
  query_id: string
}

Web:

export interface QueryResult {
  stream: ReadableStream
  query_id: string
}

Ping

Метод ping, предназначенный для проверки статуса подключения, возвращает true, если сервер доступен.

Если сервер недоступен, подлежающая ошибка также включается в результат.

type PingResult =
  | { success: true }
  | { success: false; error: Error }

/** Parameters for the health-check request - using the built-in `/ping` endpoint. 
 *  This is the default behavior for the Node.js version. */
export type PingParamsWithEndpoint = {
  select: false
  /** AbortSignal instance to cancel a request in progress. */
  abort_signal?: AbortSignal
  /** Additional HTTP headers to attach to this particular request. */
  http_headers?: Record<string, string>
}
/** Parameters for the health-check request - using a SELECT query.
 *  This is the default behavior for the Web version, as the `/ping` endpoint does not support CORS.
 *  Most of the standard `query` method params, e.g., `query_id`, `abort_signal`, `http_headers`, etc. will work, 
 *  except for `query_params`, which does not make sense to allow in this method. */
export type PingParamsWithSelectQuery = { select: true } & Omit<
  BaseQueryParams,
  'query_params'
>
export type PingParams = PingParamsWithEndpoint | PingParamsWithSelectQuery

interface ClickHouseClient {
  ping(params?: PingParams): Promise<PingResult>
}

Ping может быть полезным инструментом для проверки доступности сервера, когда приложение запускается, особенно с ClickHouse Cloud, где экземпляр может быть в ожидании и проснется после пинга: в этом случае вы можете попробовать снова несколько раз с задержкой между попытками.

Обратите внимание, что по умолчанию версия для Node.js использует конечную точку /ping, в то время как веб-версия использует простой запрос SELECT 1, чтобы достичь аналогичного результата, так как конечная точка /ping не поддерживает CORS.

Пример: (Node.js/Web) Простой ping к экземпляру сервера ClickHouse. Примечание: для веб-версии захваченные ошибки будут различаться. Исходный код.

const result = await client.ping();
if (!result.success) {
  // process result.error
}

Пример: Если вы хотите также проверить учетные данные при вызове метода ping, или указать дополнительные параметры, такие как query_id, вы можете использовать его следующим образом:

const result = await client.ping({ select: true, /* query_id, abort_signal, http_headers, or any other query params */ });

Метод ping позволит использовать большинство стандартных параметров метода query - смотрите определение типов PingParamsWithSelectQuery.

Закрытие (только Node.js)

Закрывает все открытые соединения и освобождает ресурсы. Не выполняет никаких операций в веб-версии.

await client.close()

Потоковые файлы (только Node.js)

В репозитории клиента есть несколько примеров потоковой передачи файлов с популярными форматами данных (NDJSON, CSV, Parquet).

Потоковая передача других форматов в файл должна быть аналогична формату Parquet, единственное различие будет в формате, используемом для вызова query (JSONEachRow, CSV и т.д.) и имени выходного файла.

Поддерживаемые форматы данных

Клиент обрабатывает форматы данных как JSON или текст.

Если вы указываете format как один из форматов семейства JSON (JSONEachRow, JSONCompactEachRow и т.д.), клиент будет сериализовать и десериализовать данные во время передачи по сети.

Данные, предоставленные в "сырьевых" текстовых форматах (CSV, TabSeparated и CustomSeparated), отправляются по сети без дополнительных преобразований.

подсказка

Может возникнуть путаница между JSON как общим форматом и форматом JSON ClickHouse.

Клиент поддерживает потоковые JSON объекты с такими форматами, как JSONEachRow (см. сводку таблицы для других форматов, удобных для потоковой передачи; также смотрите примеры с select_streaming_ в репозитории клиента).

Только форматы, такие как ClickHouse JSON и несколько других, представлены как единый объект в ответе и не могут быть переданы потоком клиентом.

ФорматВход (массив)Вход (объект)Вход/Выход (Поток)Выход (JSON)Выход (текст)
JSON✔️✔️✔️
JSONCompact✔️✔️✔️
JSONObjectEachRow✔️✔️✔️
JSONColumnsWithMetadata✔️✔️✔️
JSONStrings❌️✔️✔️
JSONCompactStrings✔️✔️
JSONEachRow✔️✔️✔️✔️
JSONEachRowWithProgress❌️✔️ ❗- см. ниже✔️✔️
JSONStringsEachRow✔️✔️✔️✔️
JSONCompactEachRow✔️✔️✔️✔️
JSONCompactStringsEachRow✔️✔️✔️✔️
JSONCompactEachRowWithNames✔️✔️✔️✔️
JSONCompactEachRowWithNamesAndTypes✔️✔️✔️✔️
JSONCompactStringsEachRowWithNames✔️✔️✔️✔️
JSONCompactStringsEachRowWithNamesAndTypes✔️✔️✔️✔️
CSV✔️✔️
CSVWithNames✔️✔️
CSVWithNamesAndTypes✔️✔️
TabSeparated✔️✔️
TabSeparatedRaw✔️✔️
TabSeparatedWithNames✔️✔️
TabSeparatedWithNamesAndTypes✔️✔️
CustomSeparated✔️✔️
CustomSeparatedWithNames✔️✔️
CustomSeparatedWithNamesAndTypes✔️✔️
Parquet✔️✔️❗- см. ниже

Для Parquet основное использование для выборок, вероятно, будет запись результирующего потока в файл. Смотрите пример в репозитории клиента.

JSONEachRowWithProgress является форматом только для вывода, который поддерживает отчет о прогрессе в потоке. Смотрите этот пример для получения более подробной информации.

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

Поддерживаемые типы данных ClickHouse

примечание

Связанный тип JS имеет значение для любых форматов JSON*, кроме тех, которые представляют все как строки (например, JSONStringEachRow)

ТипСтатусТип JS
UInt8/16/32✔️number
UInt64/128/256✔️ ❗- см. нижеstring
Int8/16/32✔️number
Int64/128/256✔️ ❗- см. нижеstring
Float32/64✔️number
Decimal✔️ ❗- см. нижеnumber
Boolean✔️boolean
String✔️string
FixedString✔️string
UUID✔️string
Date32/64✔️string
DateTime32/64✔️ ❗- см. нижеstring
Enum✔️string
LowCardinality✔️string
Array(T)✔️T[]
(new) JSON✔️object
Variant(T1, T2...)✔️T (в зависимости от варианта)
Dynamic✔️T (в зависимости от варианта)
Nested✔️T[]
Tuple(T1, T2, ...)✔️[T1, T2, ...]
Tuple(n1 T1, n2 T2...)✔️{ n1: T1; n2: T2; ...}
Nullable(T)✔️Тип JS для T или null
IPv4✔️string
IPv6✔️string
Point✔️[ number, number ]
Ring✔️Array<Point>
Polygon✔️Array<Ring>
MultiPolygon✔️Array<Polygon>
Map(K, V)✔️Record<K, V>
Time/Time64✔️string

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

Смотрите также:

Предупреждения по типам Date/Date32

Так как клиент вставляет значения без дополнительного преобразования типов, столбцы типа Date/Date32 могут быть вставлены только как строки.

Пример: Вставить значение типа Date. Исходный код

await client.insert({
  table: 'my_table',
  values: [ { date: '2022-09-05' } ],
  format: 'JSONEachRow',
})

Тем не менее, если вы используете столбцы DateTime или DateTime64, вы можете использовать как строки, так и объекты даты JS. Объекты даты JS могут быть переданы в insert без изменений с установленным date_time_input_format в значение best_effort. Смотрите этот пример для получения более подробной информации.

Предупреждения по типам Decimal*

Можно вставлять Decimal с использованием форматов семейства JSON*. Предположим, что у нас есть таблица, определенная как:

CREATE TABLE my_table
(
  id     UInt32,
  dec32  Decimal(9, 2),
  dec64  Decimal(18, 3),
  dec128 Decimal(38, 10),
  dec256 Decimal(76, 20)
)
ENGINE MergeTree()
ORDER BY (id)

Мы можем вставлять значения без потери точности, используя строковое представление:

await client.insert({
  table: 'my_table',
  values: [{
    id: 1,
    dec32:  '1234567.89',
    dec64:  '123456789123456.789',
    dec128: '1234567891234567891234567891.1234567891',
    dec256: '12345678912345678912345678911234567891234567891234567891.12345678911234567891',
  }],
  format: 'JSONEachRow',
})

Однако при запросе данных в форматах JSON* ClickHouse по умолчанию будет возвращать Decimals как числа, что может привести к потере точности. Чтобы избежать этого, вы можете привести Decimals к строке в запросе:

await client.query({
  query: `
    SELECT toString(dec32)  AS decimal32,
           toString(dec64)  AS decimal64,
           toString(dec128) AS decimal128,
           toString(dec256) AS decimal256
    FROM my_table
  `,
  format: 'JSONEachRow',
})

Смотрите этот пример для получения более подробной информации.

Целочисленные типы: Int64, Int128, Int256, UInt64, UInt128, UInt256

Хотя сервер может принимать их как числа, они возвращаются как строки в выходных форматах семейства JSON*, чтобы избежать переполнения целых чисел, поскольку максимальные значения для этих типов больше, чем Number.MAX_SAFE_INTEGER.

Это поведение, однако, может быть изменено с помощью настройки output_format_json_quote_64bit_integers.

Пример: Настройка формата JSON для 64-битных чисел.

const resultSet = await client.query({
  query: 'SELECT * from system.numbers LIMIT 1',
  format: 'JSONEachRow',
})

expect(await resultSet.json()).toEqual([ { number: '0' } ])
const resultSet = await client.query({
  query: 'SELECT * from system.numbers LIMIT 1',
  format: 'JSONEachRow',
  clickhouse_settings: { output_format_json_quote_64bit_integers: 0 },
})

expect(await resultSet.json()).toEqual([ { number: 0 } ])

Настройки ClickHouse

Клиент может настраивать поведение ClickHouse через настройки. Настройки могут быть установлены на уровне экземпляра клиента, чтобы они применялись ко всем запросам, отправляемым в ClickHouse:

const client = createClient({
  clickhouse_settings: {}
})

Или настройку можно настроить на уровне запроса:

client.query({
  clickhouse_settings: {}
})

Файл декларации типов со всеми поддерживаемыми настройками ClickHouse можно найти здесь.

к сведению

Убедитесь, что у пользователя, от имени которого выполняются запросы, достаточно прав для изменения настроек.

Расширенные темы

Запросы с параметрами

Вы можете создать запрос с параметрами и передать значения из клиентского приложения. Это позволяет избежать форматирования запроса с конкретными динамическими значениями на стороне клиента.

Отформатируйте запрос как обычно, затем разместите значения, которые вы хотите передать из параметров приложения в запрос в фигурных скобках в следующем формате:

{<name>: <data_type>}

где:

  • name — идентификатор заполнителя.
  • data_type - Тип данных значения параметра приложения.

Пример: Запрос с параметрами. Исходный код.

await client.query({
  query: 'SELECT plus({val1: Int32}, {val2: Int32})',
  format: 'CSV',
  query_params: {
    val1: 10,
    val2: 20,
  },
})

Проверьте https://clickhouse.com/docs/interfaces/cli#cli-queries-with-parameters-syntax для получения дополнительных деталей.

Сжатие

NB: сжатие запросов в настоящее время недоступно в веб-версии. Сжатие ответов работает как обычно. Версия для Node.js поддерживает оба варианта.

Приложения для работы с большими наборами данных по сети могут извлечь выгоду из включения сжатия. В настоящее время поддерживается только GZIP с использованием zlib.

createClient({
  compression: {
    response: true,
    request: true
  }
})

Параметры конфигурации:

  • response: true указывает серверу ClickHouse отвечать с сжатым ответом. Значение по умолчанию: response: false
  • request: true включает сжатие в теле запроса клиента. Значение по умолчанию: request: false

Логирование (только Node.js)

к сведению

Логирование является экспериментальной функцией и может измениться в будущем.

Реализация логгера по умолчанию записывает записи журналов в stdout через методы console.debug/info/warn/error. Вы можете настроить логику логирования, предоставив класс LoggerClass, и выбрать желаемый уровень журнала через параметр level (по умолчанию OFF):

import type { Logger } from '@clickhouse/client'

// All three LogParams types are exported by the client
interface LogParams {
  module: string
  message: string
  args?: Record<string, unknown>
}
type ErrorLogParams = LogParams & { err: Error }
type WarnLogParams = LogParams & { err?: Error }

class MyLogger implements Logger {
  trace({ module, message, args }: LogParams) {
    // ...
  }
  debug({ module, message, args }: LogParams) {
    // ...
  }
  info({ module, message, args }: LogParams) {
    // ...
  }
  warn({ module, message, args }: WarnLogParams) {
    // ...
  }
  error({ module, message, args, err }: ErrorLogParams) {
    // ...
  }
}

const client = createClient({
  log: {
    LoggerClass: MyLogger,
    level: ClickHouseLogLevel
  }
})

В настоящее время клиент будет регистрировать следующие события:

  • TRACE - информация низкого уровня о жизненном цикле сокетов Keep-Alive
  • DEBUG - информация о ответах (без заголовков аутентификации и информации о хосте)
  • INFO - в основном не используется, будет выводить текущий уровень журнала при инициализации клиента
  • WARN - нефатальные ошибки; неудачный запрос ping регистрируется как предупреждение, так как основанная ошибка включена в возвращаемый результат
  • ERROR - фатальные ошибки из методов query/insert/exec/command, такие как неудачный запрос

Вы можете найти реализацию логгера по умолчанию здесь.

TLS сертификаты (только Node.js)

Клиент Node.js опционально поддерживает как базовый (только Сертификат Удостоверяющего Центра) так и взаимный (Сертификат Удостоверяющего Центра и клиентские сертификаты) TLS.

Пример базовой конфигурации TLS, предполагая, что у вас есть сертификаты в папке certs и файл CA называется CA.pem:

const client = createClient({
  url: 'https://<hostname>:<port>',
  username: '<username>',
  password: '<password>', // if required
  tls: {
    ca_cert: fs.readFileSync('certs/CA.pem'),
  },
})

Пример конфигурации взаимного TLS с использованием клиентских сертификатов:

const client = createClient({
  url: 'https://<hostname>:<port>',
  username: '<username>',
  tls: {
    ca_cert: fs.readFileSync('certs/CA.pem'),
    cert: fs.readFileSync(`certs/client.crt`),
    key: fs.readFileSync(`certs/client.key`),
  },
})

Смотрите полные примеры для базового и взаимного TLS в репозитории.

Настройка Keep-alive (только Node.js)

Клиент по умолчанию включает Keep-Alive в подлежащем HTTP-агенте, что означает, что подключенные сокеты будут повторно использоваться для последующих запросов, а заголовок Connection: keep-alive будет отправлен. Сокеты, которые находятся в режиме ожидания, будут оставаться в пуле соединений по умолчанию в течение 2500 миллисекунд (см. заметки об изменении этой опции).

keep_alive.idle_socket_ttl должно иметь значение значительно ниже, чем конфигурация сервера/балансировщика нагрузки. Основная причина заключается в том, что из-за HTTP/1.1 сервер может закрывать сокеты без уведомления клиента; если сервер или балансировщик нагрузки закрывает соединение до того, как клиент, клиент может пытаться повторно использовать закрытый сокет, что приведет к ошибке socket hang up.

Если вы изменяете keep_alive.idle_socket_ttl, имейте в виду, что оно всегда должно быть синхронизировано с вашей конфигурацией Keep-Alive на сервере/балансировщике нагрузки, и оно должно быть всегда ниже этого значения, обеспечивая тем самым, что сервер никогда не закрывает открытое соединение первым.

Настройка idle_socket_ttl

Клиент устанавливает keep_alive.idle_socket_ttl в 2500 миллисекунд, так как это может считаться самым безопасным значением по умолчанию; на стороне сервера keep_alive_timeout может быть установлен на минимально 3 секунды в версиях ClickHouse до 23.11 без изменений в config.xml.

предупреждение

Если вам нравится производительность и вы не испытываете никаких проблем, рекомендуется не увеличивать значение настройки keep_alive.idle_socket_ttl, так как это может привести к потенциальным ошибкам "Socket hang-up"; кроме того, если ваше приложение отправляет много запросов и между ними нет большого времени простоя, значение по умолчанию должно быть достаточным, так как сокеты не будут находиться в ожидании достаточно долго, и клиент будет поддерживать их в пуле.

Вы можете найти правильное значение таймаута Keep-Alive в заголовках ответа сервера, запустив следующую команду:

curl -v --data-binary "SELECT 1" <clickhouse_url>

Проверьте значения заголовков Connection и Keep-Alive в ответе. Например:

< Connection: Keep-Alive
< Keep-Alive: timeout=10

В данном случае keep_alive_timeout составляет 10 секунд, и вы можете попробовать увеличить keep_alive.idle_socket_ttl до 9000 или даже 9500 миллисекунд, чтобы держать находящиеся в ожидании сокеты открытыми немного дольше, чем по умолчанию. Следите за потенциальными ошибками "Socket hang-up", которые будут указывать на то, что сервер закрывает соединения раньше клиента, и уменьшайте значение, пока ошибки не исчезнут.

Устранение неполадок

Если вы испытываете ошибки socket hang up, даже используя последнюю версию клиента, есть несколько вариантов решения этой проблемы:

  • Включите логи с уровнем журнала не ниже WARN. Это позволит проверить, есть ли в коде приложения неиспользуемый или зависший поток: уровень транспортного слоя будет регистрировать это на уровне WARN, так как это может привести к закрытию сокета сервером. Вы можете включить логирование в конфигурации клиента следующим образом:
const client = createClient({
  log: { level: ClickHouseLogLevel.WARN },
})
  • Проверьте ваш код приложения с включенным правилом ESLint no-floating-promises, которое поможет выявить необработанные промисы, которые могут привести к зависшим потокам и сокетам.

  • Немного уменьшите значение настройки keep_alive.idle_socket_ttl в конфигурации сервера ClickHouse. В определенных ситуациях, например, при высокой сетевой задержке между клиентом и сервером, может быть полезно уменьшить keep_alive.idle_socket_ttl еще на 200–500 миллисекунд, исключая ситуацию, когда исходящий запрос может получить сокет, который сервер собирается закрыть.

  • Если эта ошибка происходит во время длительных запросов без данных, входящих или выходящих (например, длительный INSERT FROM SELECT), это может быть связано с тем, что балансировщик нагрузки закрывает неиспользуемые соединения. Вы можете попробовать принудительно передавать некоторые данные во время длительных запросов, используя комбинацию следующих настроек ClickHouse:

const client = createClient({
  // Here we assume that we will have some queries with more than 5 minutes of execution time
  request_timeout: 400_000,
  /** These settings in combination allow to avoid LB timeout issues in case of long-running queries without data coming in or out,
   *  such as `INSERT FROM SELECT` and similar ones, as the connection could be marked as idle by the LB and closed abruptly.
   *  In this case, we assume that the LB has idle connection timeout of 120s, so we set 110s as a "safe" value. */
  clickhouse_settings: {
    send_progress_in_http_headers: 1,
    http_headers_progress_interval_ms: '110000', // UInt64, should be passed as a string
  },
})

Имейте в виду, что общий размер полученных заголовков имеет предел в 16КБ в последних версиях Node.js; после определенного количества полученных заголовков прогресса, которое было около 70-80 в наших тестах, будет сгенерировано исключение.

Также возможно использовать совершенно другой подход, полностью избегая времени ожидания по сети; это можно сделать, воспользовавшись "функцией" интерфейса HTTP, которая не отменяет мутации, когда соединение потеряно. Смотрите этот пример (часть 2) для получения более подробной информации.

  • Функция Keep-Alive может быть полностью отключена. В этом случае клиент также добавит заголовок Connection: close ко всем запросам, и подлежащий HTTP-агент не будет повторно использовать соединения. Настройка keep_alive.idle_socket_ttl будет игнорироваться, так как не будет неиспользуемых сокетов. Это приведет к дополнительным накладным расходам, так как для каждого запроса будет устанавливаться новое соединение.
const client = createClient({
  keep_alive: {
    enabled: false,
  },
})

Права доступа только для чтения

При использовании клиента с пользователем readonly=1 компрессия ответов не может быть включена, так как для этого требуется настройка enable_http_compression. Следующая конфигурация приведет к ошибке:

const client = createClient({
  compression: {
    response: true, // won't work with a readonly=1 user
  },
})

Смотрите пример с дополнительными акцентами на ограничениях пользователя readonly=1.

Прокси с путём

Если ваш экземпляр ClickHouse находится за прокси, и у него есть путь в URL, как, например, http://proxy:8123/clickhouse_server, укажите clickhouse_server как параметр конфигурации pathname (с ведущим слешем или без); в противном случае, если он указан непосредственно в url, он будет считаться параметром database. Поддерживаются несколько сегментов, например, /my_proxy/db.

const client = createClient({
  url: 'http://proxy:8123',
  pathname: '/clickhouse_server',
})

Обратный прокси с аутентификацией

Если перед вашим развертыванием ClickHouse есть обратный прокси с аутентификацией, вы можете использовать настройку http_headers для предоставления необходимых заголовков:

const client = createClient({
  http_headers: {
    'My-Auth-Header': '...',
  },
})

Пользовательский HTTP/HTTPS агент (экспериментально, только Node.js)

предупреждение

Это экспериментальная функция, которая может измениться в будущем с несовместимыми изменениями. Реализация по умолчанию и настройки, предоставляемые клиентом, должны быть достаточны для большинства случаев использования. Используйте эту функцию только в том случае, если вы уверены, что она вам нужна.

По умолчанию клиент настроит подлежащий HTTP(s) агент, используя настройки, указанные в конфигурации клиента (такие как max_open_connections, keep_alive.enabled, tls), который будет обрабатывать соединения с сервером ClickHouse. Кроме того, если используются TLS сертификаты, подлежащий агент будет настроен с необходимыми сертификатами, и соответствующие заголовки аутентификации TLS будут применены.

После версии 1.2.0 возможно предоставить пользовательский HTTP(s) агент клиенту, заменяя стандартный подлежащий. Это может быть полезно в случае сложности сетевых настроек. Применяются следующие условия, если предоставлен пользовательский агент:

  • Опции max_open_connections и tls не будут иметь никакого эффекта и будут игнорироваться клиентом, так как являются частью конфигурации подлежащего агента.
  • keep_alive.enabled будет только регулировать значение по умолчанию заголовка Connection (true -> Connection: keep-alive, false -> Connection: close).
  • Хотя управление неиспользуемыми сокетами Keep-Alive по-прежнему будет работать (так как это не привязано к агенту, а к конкретному сокету), теперь его можно полностью отключить, установив значение keep_alive.idle_socket_ttl равным 0.

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

Использование пользовательского HTTP(s) агента без сертификатов:

const agent = new http.Agent({ // or https.Agent
  keepAlive: true,
  keepAliveMsecs: 2500,
  maxSockets: 10,
  maxFreeSockets: 10,
})
const client = createClient({
  http_agent: agent,
})

Использование пользовательского HTTPS агента с базовым TLS и сертификатом CA:

const agent = new https.Agent({
  keepAlive: true,
  keepAliveMsecs: 2500,
  maxSockets: 10,
  maxFreeSockets: 10,
  ca: fs.readFileSync('./ca.crt'),
})
const client = createClient({
  url: 'https://myserver:8443',
  http_agent: agent,
  // With a custom HTTPS agent, the client won't use the default HTTPS connection implementation; the headers should be provided manually
  http_headers: {
    'X-ClickHouse-User': 'username',
    'X-ClickHouse-Key': 'password',
  },
  // Important: authorization header conflicts with the TLS headers; disable it.
  set_basic_auth_header: false,
})

Использование пользовательского HTTPS агента с взаимным TLS:

const agent = new https.Agent({
  keepAlive: true,
  keepAliveMsecs: 2500,
  maxSockets: 10,
  maxFreeSockets: 10,
  ca: fs.readFileSync('./ca.crt'),
  cert: fs.readFileSync('./client.crt'),
  key: fs.readFileSync('./client.key'),
})
const client = createClient({
  url: 'https://myserver:8443',
  http_agent: agent,
  // With a custom HTTPS agent, the client won't use the default HTTPS connection implementation; the headers should be provided manually
  http_headers: {
    'X-ClickHouse-User': 'username',
    'X-ClickHouse-Key': 'password',
    'X-ClickHouse-SSL-Certificate-Auth': 'on',
  },
  // Important: authorization header conflicts with the TLS headers; disable it.
  set_basic_auth_header: false,
})

При использовании сертификатов и пользовательского HTTPS агента, вероятно, потребуется отключить заголовок авторизации по умолчанию через настройку set_basic_auth_header (введенную в 1.2.0), так как он конфликтует с заголовками TLS. Все заголовки TLS должны быть предоставлены вручную.

Известные ограничения (Node.js/web)

  • Нет сопоставителей данных для наборов результатов, используются только примитивы языка. Определённые сопоставители типов данных запланированы с поддержкой RowBinary формата.
  • Существуют некоторые предупреждения по типам Decimal* и Date* / DateTime*.
  • Когда используются форматы семейства JSON*, числа больше Int32 представляются как строки, так как максимальные значения типов Int64+ больше Number.MAX_SAFE_INTEGER. См. раздел Целочисленные типы для получения более подробной информации.

Известные ограничения (web)

  • Потоковая передача для выборок работает, но отключена для вставок (на уровне типов также).
  • Сжатие запросов отключено, и конфигурация игнорируется. Сжатие ответов работает.
  • Поддержка логирования пока отсутствует.

Советы по оптимизации производительности

  • Для уменьшения потребления памяти приложением рассмотрите возможность использования потоков для больших вставок (например, из файлов) и выборок, когда это возможно. Для слушателей событий и аналогичных сценариев асинхронные вставки могут быть еще одной хорошей опцией, позволяя минимизировать или даже полностью избежать пакетной обработки на стороне клиента. Примеры асинхронных вставок доступны в репозитории клиента, с префиксом async_insert_ в названии файла.
  • Клиент по умолчанию не включает сжатие запросов или ответов. Однако при выборке или вставке больших наборов данных вы можете рассмотреть возможность включения его через ClickHouseClientConfigOptions.compression (либо только для request, либо для response, либо для обоих).
  • Сжатие имеет значительные потери производительности. Включение его для request или response негативно скажется на скорости выборок или вставок соответственно, но уменьшит объем сетевого трафика, передаваемого приложением.

Свяжитесь с нами

Если у вас есть вопросы или нужна помощь, не стесняйтесь обращаться к нам в Community Slack (канал #clickhouse-js) или через GitHub issues.