Типы данных ClickHouse
Правильный тип колонки — это и меньше места на диске, и выше скорость.
Тип данных в ClickHouse точно задаёт, сколько байт занимает значение и как оно сжимается; экономный тип = меньше чтения с диска.
Числа: размер имеет значение
В отличие от «универсального» INTEGER, ClickHouse предлагает числа разной ширины, и вы выбираете минимально достаточную:
| Тип | Размер | Диапазон (примерно) |
UInt8 | 1 байт | 0..255 |
UInt32 | 4 байта | 0..4 млрд |
Int64 | 8 байт | ±9·10^18 |
Float64 | 8 байт | дробные |
Если значение колонки — возраст (0–120), хранить его в UInt8, а не в Int64: экономия в 8 раз на каждой строке. На миллиардах строк это гигабайты.
Строки, даты, время
String— строка произвольной длины.FixedString(N)— строка ровно N байт (например, код страны).Date— дата (2 байта),DateTime— дата-время до секунды (4 байта),DateTime64— с долями секунды.
Особые типы ClickHouse
LowCardinality
Если в колонке мало разных значений (страна, браузер, статус), оберните тип в LowCardinality. ClickHouse заведёт словарь уникальных значений и будет хранить компактные номера вместо повторяющихся строк — меньше места и быстрее GROUP BY.
country LowCardinality(String)
status LowCardinality(String)Nullable
По умолчанию колонки не допускают NULL. Чтобы разрешить пропуски, оборачивают в Nullable — но это стоит дополнительного байта-флага на значение и замедляет работу. Используйте только когда NULL действительно нужен.
age UInt8 -- NULL запрещён
email Nullable(String) -- NULL разрешён, но дорожеEnum
Enum8/Enum16 — фиксированный набор строковых меток, хранящихся как маленькие числа: компактно и с проверкой допустимых значений.
Иллюстрация экономии
Прикинем экономию места при выборе UInt8 вместо Int64 на 100 млн строк (чистый Python):
rows = 100_000_000
int64_bytes = rows * 8
uint8_bytes = rows * 1
print("Int64:", int64_bytes // (1024*1024), "МБ")
print("UInt8:", uint8_bytes // (1024*1024), "МБ")
print("Экономия в", int64_bytes // uint8_bytes, "раз")Вывод:
Int64: 762 МБ UInt8: 95 МБ Экономия в 8 раз
Как работает под капотом
Каждая колонка хранится в своём типе и сжимается. Узкий тип не только занимает меньше места до сжатия, но и лучше векторизуется. LowCardinality фактически реализует словарное кодирование, которое в строковых базах пришлось бы делать руками через справочные таблицы.
Частые ошибки
- Всё подряд в
Nullable. Лишние NULL-флаги раздувают данные и тормозят запросы; включайте Nullable осознанно. - Хранить мелкие числа в широких типах. Возраст в Int64 — восьмикратный перерасход.
- Категории как обычный
String. Для колонок с малым числом значений почти всегда лучшеLowCardinality.
Итоги
- Выбирайте минимально достаточную ширину числового типа.
LowCardinality— для колонок с малым числом различных значений.Nullable— только когда NULL реально нужен (он стоит ресурсов).- Точный тип = меньше диска и быстрее запросы.