Используйте JSON, когда это уместно
В ClickHouse теперь есть встроенный тип столбца JSON, предназначенный для полуструктурированных и динамических данных. Важно уточнить, что это тип столбца, а не формат данных — вы можете вставлять JSON в ClickHouse как строку или через поддерживаемые форматы, такие как JSONEachRow, но это само по себе не означает использование типа столбца JSON. Тип JSON следует применять только тогда, когда структура ваших данных является динамической, а не когда вы просто храните JSON.
Когда использовать тип JSON
Тип JSON предназначен для выполнения запросов, фильтрации и агрегации отдельных полей внутри JSON-объектов с динамической или непредсказуемой структурой. Это достигается за счёт разбиения JSON-объектов на отдельные подстолбцы, что значительно сокращает объём считываемых данных и ускоряет запросы по выбранным полям по сравнению с альтернативами, такими как Map или разбор строк.
Однако это связано с важными компромиссами:
- Более медленные операции
INSERT— Разбиение JSON на подстолбцы, вывод типов и управление гибкими структурами хранения делает вставки медленнее по сравнению с хранением JSON в простом столбце типаString. - Медленнее при чтении целых объектов — Если нужно извлекать полные JSON-документы (а не отдельные поля), тип
JSONработает медленнее, чем чтение из столбца типаString. Накладные расходы на реконструкцию объектов из отдельных подстолбцов не дают преимуществ, если вы не выполняете запросы на уровне отдельных полей. - Накладные расходы на хранение — Поддержка отдельных подстолбцов добавляет структурные накладные расходы по сравнению с хранением JSON как одного строкового значения.
Используйте тип JSON, когда:
- Ваши данные имеют динамическую или непредсказуемую структуру с различающимися ключами в разных документах
- Типы полей или схемы со временем изменяются или различаются между записями
- Вам нужно выполнять запросы, фильтрацию или агрегирование по конкретным путям внутри объектов JSON, структуру которых невозможно заранее предсказать
- Ваш сценарий использования включает полуструктурированные данные, такие как логи, события или пользовательский контент с непоследовательными схемами
Используйте столбец String (или структурированные типы), когда:
- Структура ваших данных известна и стабильна — в этом случае используйте обычные столбцы или типы
Tuple,Array,DynamicлибоVariant - Документы
JSONрассматриваются как непрозрачные двоичные объекты, которые только сохраняются и извлекаются целиком без анализа на уровне полей - Вам не нужно выполнять запросы или фильтрацию по отдельным полям JSON в базе данных
JSONиспользуется только как формат передачи/хранения и не анализируется в ClickHouse
Если JSON — это непрозрачный документ, который не анализируется внутри базы данных и только сохраняется и затем извлекается, его следует хранить в столбце типа String. Преимущества типа JSON проявляются только тогда, когда вам нужно эффективно выполнять запросы, фильтрацию или агрегацию по конкретным полям внутри динамических структур JSON.
Вы также можете комбинировать подходы — использовать стандартные столбцы для предсказуемых верхнеуровневых полей и столбец JSON для динамических частей полезной нагрузки.
Соображения и советы по использованию JSON
Тип JSON обеспечивает эффективное столбцовое хранение за счёт разворачивания путей в подстолбцы. Но с гибкостью приходит ответственность. Чтобы использовать его эффективно:
- Явно указывайте типы путей, используя подсказки в определении столбца, чтобы задавать типы для известных подстолбцов и избегать ненужного вывода типов.
- Пропускайте пути, если вам не нужны их значения, с помощью SKIP и SKIP REGEXP, чтобы сократить объём хранения и повысить производительность.
- Избегайте слишком большого значения
max_dynamic_paths— большие значения увеличивают потребление ресурсов и снижают эффективность. В качестве эмпирического правила держите его ниже 10 000.
Подсказки типов дают больше, чем просто способ избежать ненужного вывода типов — они полностью устраняют издержки на косвенное хранение и обработку. JSON‑пути с подсказками типов всегда хранятся так же, как обычные столбцы, устраняя необходимость в столбцах‑дискриминаторах или динамическом разрешении во время выполнения запроса. Это означает, что при хорошо заданных подсказках типов вложенные поля JSON достигают такой же производительности и эффективности, как если бы они изначально моделировались как поля верхнего уровня. В результате для наборов данных, которые в целом однородны, но всё же выигрывают от гибкости JSON, подсказки типов предоставляют удобный способ сохранить производительность без необходимости переработки схемы или конвейера приёма.
Расширенные возможности
- JSON-столбцы могут использоваться в первичных ключах, как и любые другие столбцы. Кодеки не могут быть указаны для подстолбцов.
- Они поддерживают интроспекцию с помощью функций вроде
JSONAllPathsWithTypes()иJSONDynamicPaths(). - Вы можете считывать вложенные подобъекты, используя синтаксис
.^. - Синтаксис запросов может отличаться от стандартного SQL и может требовать специального приведения типов или операторов для вложенных полей.
Для получения дополнительной информации см. документацию по JSON в ClickHouse или ознакомьтесь с нашей статьёй в блоге Новый мощный тип данных JSON для ClickHouse.
Примеры
Рассмотрим следующий образец JSON, представляющий строку из набора данных Python PyPI:
Предположим, что эта схема фиксирована и типы могут быть чётко определены. Даже если данные находятся в формате NDJSON (одна JSON-строка в каждой строке), нет необходимости использовать тип JSON для такой схемы. Просто задайте схему, используя обычные типы.
и вставьте строки JSON:
Рассмотрим набор данных arXiv, содержащий 2,5 млн научных статей. Каждая строка этого набора данных в формате NDJSON соответствует одной опубликованной научной статье. Пример строки показан ниже:
Хотя приведённый здесь JSON и сложный, с вложенными структурами, он предсказуем. Количество и тип полей не изменятся. В этом примере мы могли бы использовать тип JSON, но также можем просто явно задать структуру с помощью типов Tuples и Nested:
Снова вставим данные в формате JSON:
Предположим, что добавлен ещё один столбец под названием tags. Если бы это был просто список строк, мы могли бы смоделировать его как Array(String), но давайте предположим, что вы можете добавлять произвольные структуры тегов со смешанными типами (обратите внимание, что score — это строка или целое число). Наш модифицированный JSON-документ:
В этом случае мы могли бы смоделировать документы arXiv либо полностью в формате JSON, либо просто добавить столбец JSON tags. Ниже приведены оба варианта:
Мы указываем подсказку типа данных для столбца update_date в JSON-определении, так как используем его в сортировке / первичном ключе. Это помогает ClickHouse знать, что этот столбец не может быть NULL, и гарантирует, что система понимает, какой подстолбец update_date использовать (для каждого типа их может быть несколько, поэтому без этого возникает неоднозначность).
Мы можем выполнить вставку в эту таблицу и просмотреть автоматически выведенную схему с помощью функции JSONAllPathsWithTypes и формата вывода PrettyJSONEachRow:
В качестве альтернативы мы могли бы смоделировать это, используя нашу предыдущую схему и столбец JSON tags. Такой подход обычно предпочтителен, так как он сводит к минимуму объём работы по автоматическому выводу, которую должен выполнять ClickHouse:
Теперь мы можем определить типы подстолбца tags.