Добавление данных в ClickHouse®
Для обычной вставки данных в таблицы используйте запрос INSERT INTO:
INSERT INTO db_name.table_name VALUES (v11, v12, v13), (v21, v22, v23), ...
Запросы на вставку рекомендуется отправлять не чаще одного раза в секунду. Чтобы объединить мелкие запросы в один большой, используйте буферизацию.
Подробнее о запросе INSERT INTO см. в документации ClickHouse®
Вставка данных из файла
Для вставки данных в таблицу из локального файла используйте запрос INSERT INTO вида:
INSERT INTO db_name.table_name FROM INFILE '<полный_путь_к_файлу>'
[COMPRESSION '<формат_сжатия>'] FORMAT <формат_данных>;
Опция COMPRESSION позволяет передавать сжатые файлы. Используйте ее, чтобы загружать большие объемы информации. Опция поддерживается при работе через clickhouse-clientnone, gzip, deflate, br, xz, zstd, lz4, bz2.
Список поддерживаемых форматов данных приведен в документации ClickHouse®
Вставка данных с использованием буферизации
При вставке данных в ClickHouse® часть вычислительных ресурсов расходуется на выполнение служебных операций. При выполнении каждого INSERT-запроса ClickHouse® создает в хранилище отдельный кусок данных. Помимо строк таблицы такой кусок содержит ряд вспомогательных файлов с метаданными. Затем ClickHouse® объединяет куски данных в фоновом режиме. Чем больше потребуется операций объединения, тем больше будет задействовано ресурсов.
В результате тысяча запросов на вставку одной строки создаст большую нагрузку на кластер, чем один запрос на вставку тысячи строк. Поэтому рекомендуется вставлять данные в таблицу большими порциями — от 1000 до 100 000 строк.
Если данные поступают малыми порциями от разных источников, используйте один из механизмов буферизации:
- (рекомендуется) асинхронная вставка;
- буферные таблицы.
Асинхронная вставка данных
Если для пользователя установлена настройка Async insert, то все запросы на вставку от этого пользователя сначала попадают в буфер в оперативной памяти. Данные из буфера сбрасываются в таблицу при выполнении одного из условий:
- Размер буфера достиг значения настройки Async insert max data size.
- С момента первого после сброса данных
INSERT-запроса прошло время, указанное в настройке Async insert busy timeout.
Чтобы включить асинхронную вставку данных, установите значение настройки Async insert на 1.
При использовании асинхронных вставок недоступна дедупликация строк
Подробную информацию об асинхронной вставке данных см. в документации ClickHouse®
Вставка данных через буферную таблицу
Буферная таблица создается в оперативной памяти, накапливает поступающие в нее данные и сбрасывает их в основную таблицу при выполнении заданных условий.
Для создания буферной таблицы используется табличный движок Buffer, который принимает на вход следующие основные параметры:
Buffer(database, table, num_layers, min_time, max_time, min_rows, max_rows, min_bytes, max_bytes)
Где:
database— имя БД.table— имя таблицы, в которую будут сброшены данные.num_layers— количество буферов. Физически таблица хранится в памяти в виде нескольких независимых буферов.min_time,max_time,min_rows,max_rows,min_bytesиmax_bytes— параметры, определяющие условия сброса данных в основную таблицу. Время измеряется в секундах.
Сброс данных в основную таблицу происходит при достижении всех минимальных значений, либо хотя бы одного максимального. Если объем поступающей порции данных превышает max_rows или max_bytes, то данные не попадают в буфер, а записываются напрямую в основную таблицу.
Информацию о дополнительных параметрах движка и ограничениях таблиц на движке Buffer см. в документации ClickHouse®
Пример
-
Создайте обычную таблицу
usersв базе данныхdb1:CREATE TABLE IF NOT EXISTS db1.users (id UInt64, name String) ENGINE = MergeTree() ORDER BY id; -
Создайте буферную таблицу
users_buffer, привязанную к основной таблицеusers:CREATE TABLE db1.users_buffer AS db1.users ENGINE = Buffer(db1, users, 1, 10, 100, 10000, 1000000, 10000000, 100000000); -
Передайте данные в буферную таблицу:
INSERT INTO db1.users_buffer VALUES (1, 'Vlad'), (2, 'John'), (3, 'Zara'); -
Проверьте данные в основной таблице, они появятся через 100 секунд (
max_time):SELECT * FROM db1.users;
Результат:
┌─id─┬─name─┐
│ 1 │ Vlad │
│ 2 │ John │
│ 3 │ Zara │
└────┴──────┘
Вставка данных с указанием схемы формата данных
Managed Service for ClickHouse® позволяет вставлять (INSERT) и выводить (SELECT) данные в различных форматах. Большинство таких форматов — самоописываемые, то есть они уже содержат в себе схему формата данных, описывающую допустимые типы данных, их порядок и представление в этом формате. Это позволяет, например, сразу делать вставку из файла.
Примечание
Схема формата данных (format schema) описывает формат ввода или вывода данных, в то время как схема данных (data scheme) описывает структуру и устройство баз данных и таблиц ClickHouse®, которые хранят эти данные. Эти понятия не являются взаимозаменяемыми.
Форматы данных Cap'n Proto
Вы можете подключить к кластеру Managed Service for ClickHouse® одну или несколько таких схем формата и использовать их для ввода и вывода требуемых данных в соответствующих форматах.
Важно
Чтобы использовать подключенные схемы формата, вставку данных в Managed Service for ClickHouse® следует производить с помощью HTTP-интерфейса
Подробнее о форматах данных см. в документации ClickHouse®
Пример работы со схемой формата при вставке данных
Пример проверялся в следующем окружении:
- Виртуальная машина в Облаке с Ubuntu 20.04 LTS.
- Bash:
5.0.16. - clickhouse-client:
20.10.2.20. - capnproto:
0.7.0. - protobuf-compiler:
3.6.1. - Python:
3.8.5; pip3:20.0.2.
Допустим, что создан однохостовый кластер Managed Service for ClickHouse® chcluster с базой данных db1 и нужно вставить данные о пользователях в таблицу db1.users. Пусть каждая запись о пользователе содержит следующую информацию:
- идентификатор пользователя
id; - имя пользователя
name.
Чтобы вставить данные о пользователях в форматах Cap'n Proto и Protobuf в таблицу db1.users:
Перед началом работы
-
Изучите формат данных, который будет использоваться при вставке, чтобы подготовить корректные схемы формата.
В этом сценарии использования для иллюстрации принимается, что:
- идентификатор пользователя
idпредставлен в виде целого беззнакового 64-битного числа (Uint64в Cap'n Proto и ClickHouse®,uint64в Protobuf); - имя пользователя
nameпредставлено в виде строки (Textв Cap'n Proto,stringв Protobuf,Stringв ClickHouse®).
Подробнее о поддерживаемых типах данных см. в документации Cap'n Proto
, Protobuf и ClickHouse® . - идентификатор пользователя
-
Подключитесь к кластеру и создайте таблицу
db1.usersнужного вида, если ее еще не существует:CREATE TABLE IF NOT EXISTS db1.users (id UInt64, name String) ENGINE = MergeTree() ORDER BY id;
Установка зависимостей
sudo apt update && sudo apt install -y python3 python3-pip capnproto protobuf-compiler && \
pip3 install protobuf varint pycapnp
Подготовка схем формата данных
-
Создайте файл с описанием схемы:
Cap'n ProtoProtobufuser.capnp@0xbec0f3f99cec4fbf; struct User { id @0 :UInt64; name @1 :Text; }Подробнее о формате файла см. в документации Cap'n Proto
.user.protosyntax = "proto3"; message User { uint64 id = 1; string name = 2; };Подробнее о формате файла см. в документации Protobuf
. -
Загрузите файл в Object Storage и получите ссылку на него.
-
Подключите схему формата данных к кластеру
chcluster:- Для схемы формата данных Cap'n Proto (файл
user.capnp) задайте имяschema-capnproto. - Для схемы формата данных Protobuf (файл
user.protobuf) задайте имяschema-protobuf.
- Для схемы формата данных Cap'n Proto (файл
Подготовка скриптов
Эти Python-скрипты подготавливают тестовые данные о пользователях в нужных форматах и вставляют их в таблицу кластера.
Примечание
Скрипты на Python приведены в демонстрационных целях. Вы можете подготовить и вставить бинарные данные в требуемом формате, создав аналогичный скрипт на другом языке программирования.
Чтобы подготовить скрипты:
-
Скомпилируйте файл схемы Protobuf
user.protoдля Python:protoc user.proto --python_out .Будет сгенерирован файл
user_pb2.py. -
Создайте файлы с кодом Python:
Cap'n ProtoProtobufcapnproto-example.pyimport requests import io import capnp from user_capnp import User DB_HOST="<FQDN_хоста_ClickHouse®>" DB_NAME="db1" DB_USER="<имя_пользователя_БД>" DB_PASS="<пароль_пользователя_БД>" CA_CERT="/usr/local/share/ca-certificates/Yandex/RootCA.crt" SCHEMA_NAME = 'schema-capnproto' SCHEMA_TYPE = "CapnProto" SCHEMA_CLASS = "User" def execute_query(query, data=None): url = 'https://{host}:8443/'.format(host=DB_HOST) params = { 'database': DB_NAME, 'query': query.strip() } auth = { 'X-ClickHouse-User': DB_USER, 'X-ClickHouse-Key': DB_PASS } rs = requests.post(url, params=params, headers=auth, data=data, verify=CA_CERT) rs.raise_for_status() def add_user(fileobj, user_id, user_name): user = User.new_message() user.id = user_id user.name = user_name fileobj.write(user.to_bytes()) message = io.BytesIO() add_user(message, 11, 'John') add_user(message, 12, 'Bob') add_user(message, 13, 'Jane') execute_query( ''' INSERT INTO {database}.users SETTINGS format_schema='{name}:{cls}' FORMAT {type} '''.format(database=DB_NAME, type=SCHEMA_TYPE, name=SCHEMA_NAME, cls=SCHEMA_CLASS), data=message.getvalue())Этот скрипт:
- Получает класс
Userиз подключенного файлаuser.capnp(from user_capnp import User). - Выполняет запросы к кластеру по HTTPS, использует SSL.
- Записывает тестовый набор данных в объект класса User (
def add_user ...) и добавляет этот объект к битовому потоку ввода-выводаmessage. - Вставляет данные из битового потока
messageв таблицуdb1.users, опираясь на данные классаUserсхемы формата данныхschema-capnprotoв кластере.
protobuf-example.pyimport requests import io import varint from user_pb2 import User DB_HOST="<FQDN_хоста_ClickHouse®>" DB_NAME="db1" DB_USER="<имя_пользователя_БД>" DB_PASS="<пароль_пользователя_БД>" CA_CERT="/usr/local/share/ca-certificates/Yandex/RootCA.crt" SCHEMA_NAME = 'schema-protobuf' SCHEMA_TYPE = "Protobuf" SCHEMA_CLASS = "User" def execute_query(query, data=None): url = 'https://{host}:8443/'.format(host=DB_HOST) params = { 'database': DB_NAME, 'query': query.strip() } auth = { 'X-ClickHouse-User': DB_USER, 'X-ClickHouse-Key': DB_PASS } rs = requests.post(url, params=params, headers=auth, data=data, verify=CA_CERT) rs.raise_for_status() def add_user(fileobj, user_id, user_name): user = User() user.id = user_id user.name = user_name fileobj.write(varint.encode(user.ByteSize())) fileobj.write(user.SerializeToString()) message = io.BytesIO() add_user(message, 21, 'Stephen') add_user(message, 22, 'Olivia') add_user(message, 23, 'Tim') execute_query( '''INSERT INTO {database}.users SETTINGS format_schema='{name}:{cls}' FORMAT {type} '''.format(database=DB_NAME, type=SCHEMA_TYPE, name=SCHEMA_NAME, cls=SCHEMA_CLASS), data=message.getvalue())Этот скрипт:
- Получает класс
Userиз подключенного файлаuser_pb2.py, который был получен после компиляции proto-файла (from user_pb2 import User). - Записывает тестовый набор данных в объект класса User (
def add_user ...) и добавляет этот объект к битовому потоку ввода-выводаmessage. - Вставляет данные из битового потока
messageв таблицуdb1.users, опираясь на данные классаUserсхемы формата данныхschema-protobufв кластере.
О том, как получить FQDN хоста, см. инструкцию.
- Получает класс
Вставка данных
-
Запустите подготовленные на предыдущем этапе скрипты:
Cap'n ProtoProtobufpython3 capnproto-example.pypython3 protobuf-example.py -
Подключитесь к кластеру и проверьте, что данные были успешно вставлены, выполнив запрос
SELECT:Cap'n ProtoProtobufSELECT * FROM db1.users; ┌─id─┬─name─┐ │ 11 │ John │ │ 12 │ Bob │ │ 13 │ Jane │ └────┴──────┘SELECT * FROM db1.users; ┌─id─┬─name────┐ │ 21 │ Stephen │ │ 22 │ Olivia │ │ 23 │ Tim │ └────┴─────────┘
ClickHouse® является зарегистрированным товарным знаком ClickHouse, Inc