Как Clickhouse хранит данные на диске

Это достаточно старая заметка, которую я нашёл в своих архивах и решил выложить. Речь идёт о старой версии Clickhouse 1.1.54198, текущая же версия: 1.1.54381, 2018-05-14. Поэтому какая-то часть выводов может оказаться не актуальной. И да, часть данных эксперимента была потеряна и в этой заметки могут быть пробелы в показаниях.

Я провёл эксперимент, в котором показывается разница в занимаемом месте на диске, скорости мержа и выполнения запросов кликхауса для аналогичных данных хранящихся в таблице состоящей из одной партиции и в нескольких. Если вкратце, то для большинства ситуаций выгоднее хранить весь датасет в одной партиции без разбивки по месячным партициям.

Connected to ClickHouse server version 1.1.54198.

Исходная таблица содержит 177 706 668 записей.

SELECT COUNT() FROM table;
┌───COUNT()─┐
│ 177706668 │
└───────────┘
1 rows in set. Elapsed: 0.038 sec. Processed 177.71 million rows, 177.71 MB (4.70 billion rows/s., 4.70 GB/s.)

Смотри количество партиций:

SELECT COUNT() FROM system.parts WHERE active AND table = 'table';
┌─COUNT()─┐
│       1 │
└─────────┘
1 rows in set. Elapsed: 0.007 sec.

Создадим 2 таблицы с аналогичной структурой: одна — контрольная, все данные в одной партиции; вторая — тестовая, данные разделены на несколько партиций.

CREATE TABLE cntrl AS table;
CREATE TABLE test AS table;

Замерим показатели файловой системы до и во время наполнения таблиц с помощью скрипта:

while true; do df -h ; sleep 2; done
while true; do du -hs /var/lib/clickhouse/data/db/test/ ; sleep 2; done
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  118G   86G  58% /

Начинаем вставку данных в контрольную таблицу:

INSERT INTO cntrl SELECT fields FROM table;
0 rows in set. Elapsed: 136.611 sec. Processed 177.71 million rows, 23.90 GB (1.30 million rows/s., 174.94 MB/s.)

Видно, что таблица отъела 25 Гб диска, но данные пока-что не сколлапсились.

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  172G   32G  85% /
SELECT COUNT() FROM system.parts WHERE active AND table = 'cntrl';
┌─COUNT()─┐
│ 13 │
└─────────┘
┌─COUNT()─┐
│ 6 │
└─────────┘

С помощью нехитрого баш-скрипта сколлапсим данные в одну партицию и снова замерим диск.

time while [[ $(clickhouse-client --database=db--query="SELECT COUNT() FROM system.parts WHERE active AND table = 'cntrl';") -gt 1 ]]; do echo 'optimize'; clickhouse-client --database=db--query="OPTIMIZE TABLE db.cntrl;"; done
optimize
optimize
real 2m13.492s
user 0m0.024s
sys 0m0.012s

Упс, система отожрала ещё 2Гб диска!

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  173G   30G  86% /

Но спустя пару минут простоя система начала освобождать диск.

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  166G   62G  82% /

Нехитрым расчётом выясним, что 177.71 million rows в несжатом виде занимают 23.90 GB, но на диске заняли всего 7Гб!

Что ж, настало время разложить эти данные по нескольким партициям методом остатка от деления. В итоге должно получиться 33 партиции.

INSERT INTO db.test SELECT fields, toDate('0000-00-00') + (uid % 1000) date, source FROM db.table;
0 rows in set. Elapsed: 215.457 sec. Processed 177.71 million rows, 23.54 GB (824.79 thousand rows/s., 109.27 MB/s.)

Время вставки данных выросло на 80 секунд (60%)! Вот это поворот, данных же оказалось на 0.36 Гб меньше. А с партициями какой-то перебор.

SELECT COUNT() FROM system.parts WHERE active AND table = 'test';
┌─COUNT()─┐
│ 231 │
└─────────┘
┌─COUNT()─┐
│ 212 │
└─────────┘

И выжрано неимоверное количество дискового ресурса.

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  173G   31G  85% /

После создания распартицианированной таблицы было выжрато 44Гб! Почти в 2 раза больше реального объёма данных!

44G /var/lib/clickhouse/data/db/test/
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  161G   43G  80% /

И внезапно увеличилось. Количество партиций осталось прежним.

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  130G   73G  65% /

Самое время запустить скрипт мержа партиций

time while [[ $(clickhouse-client --database=db--query="SELECT COUNT() FROM system.parts WHERE active AND table = 'test';") -gt 33 ]]; do echo 'optimize'; clickhouse-client --database=db--query="OPTIMIZE TABLE db._test;"; done
optimize
optimize
optimize
...
optimize
real 2m24.046s
user 0m0.500s
sys 0m0.168s

Время мержа тоже стало выше, но всего на 11 секунд.

SELECT COUNT() FROM system.parts WHERE active AND table = 'test';
┌─COUNT()─┐
│ 33 │
└─────────┘

После:

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  170G   34G  84% /

Через время:

Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  156G   48G  77% /
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  142G   62G  70% /

Поселектим немножечко.

SELECT COUNT() FROM test;
┌───COUNT()─┐
│ 177706668 │
└───────────┘
1 rows in set. Elapsed: 0.042 sec. Processed 177.71 million rows, 177.71 MB (4.19 billion rows/s., 4.19 GB/s.)
SELECT COUNT() FROM cntrl;
┌───COUNT()─┐
│ 177706668 │
└───────────┘
1 rows in set. Elapsed: 0.042 sec. Processed 177.71 million rows, 177.71 MB (4.27 billion rows/s., 4.27 GB/s.)
SELECT COUNT() FROM test WHERE uid % 1000 = 33;
┌─COUNT()─┐
│ 177172 │
└─────────┘
1 rows in set. Elapsed: 0.443 sec. Processed 177.71 million rows, 1.42 GB (400.70 million rows/s., 3.21 GB/s.)
SELECT COUNT() FROM cntrl WHERE uid % 1000 = 33;
┌─COUNT()─┐
│ 177172 │
└─────────┘
1 rows in set. Elapsed: 0.413 sec. Processed 177.71 million rows, 1.42 GB (430.47 million rows/s., 3.44 GB/s.)
SELECT COUNT() FROM test WHERE uid = 1689337;
┌─COUNT()─┐
│ 1 │
└─────────┘
1 rows in set. Elapsed: 0.006 sec. Processed 999.42 thousand rows, 8.00 MB (158.47 million rows/s., 1.27 GB/s.)
SELECT COUNT() FROM cntrl WHERE uid = 1689337;
┌─COUNT()─┐
│ 1 │
└─────────┘
1 rows in set. Elapsed: 0.001 sec. Processed 8.19 thousand rows, 65.54 KB (7.07 million rows/s., 56.56 MB/s.)
SELECT COUNT() FROM test WHERE name = 'saxon';
┌─COUNT()─┐
│ 1 │
└─────────┘
1 rows in set. Elapsed: 0.914 sec. Processed 177.71 million rows, 3.75 GB (194.36 million rows/s., 4.11 GB/s.)
SELECT COUNT() FROM cntrl WHERE name = 'saxon';
┌─COUNT()─┐
│ 1 │
└─────────┘
1 rows in set. Elapsed: 0.888 sec. Processed 177.71 million rows, 3.75 GB (200.22 million rows/s., 4.23 GB/s.)
SELECT COUNT() FROM test WHERE name != 'saxon';
┌───COUNT()─┐
│ 177706667 │
└───────────┘

По несхлопнутым данным:

1 rows in set. Elapsed: 1.307 sec. Processed 177.71 million rows, 3.75 GB (135.91 million rows/s., 2.87 GB/s.)
SELECT COUNT() cntrl WHERE name != 'saxon'
┌───COUNT()─┐
│ 177706667 │
└───────────┘
1 rows in set. Elapsed: 1.246 sec. Processed 177.71 million rows, 3.75 GB (142.63 million rows/s., 3.01 GB/s.)
SELECT SUM(is_verified) FROM cntrl;
┌─SUM(is_verified)─┐
│ 59809 │
└──────────────────┘
1 rows in set. Elapsed: 0.107 sec. Processed 177.71 million rows, 177.71 MB (1.65 billion rows/s., 1.65 GB/s.)
SELECT SUM(is_verified) FROM test;
┌─SUM(is_verified)─┐
│ 59809 │
└──────────────────┘
1 rows in set. Elapsed: 0.110 sec. Processed 177.71 million rows, 177.71 MB (1.61 billion rows/s., 1.61 GB/s.)
ls -la /var/lib/clickhouse/data/db/test/ | wc -l
216

После инсёрта:

После оптимизации: 300

27G /var/lib/clickhouse/data/db/test/

Под конец: 37

13G /var/lib/clickhouse/data/db/test/
du -hs /var/lib/clickhouse/data/db/cntrl/
12G /var/lib/clickhouse/data/db/cntrl/

Хех, такая таблица даже удаляется дольше.

DROP TABLE test;
0 rows in set. Elapsed: 0.831 sec.
DROP TABLE cntrl;
0 rows in set. Elapsed: 0.245 sec.
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  118G   86G  58% /
4
8.0K    /var/lib/clickhouse/data/db/cntrl/
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  118G   86G  58% /
206
35G     /var/lib/clickhouse/data/db/cntrl/
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  152G   51G  75% /

Система что-то схлапнула. Количество партиций не изменилось.

10
12G     /var/lib/clickhouse/data/db/cntrl/
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  129G   74G  64% /

Коллапсим!

11
24G     /var/lib/clickhouse/data/db/cntrl/
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  141G   62G  70% /

Ждём!

5
12G     /var/lib/clickhouse/data/db/cntrl/
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg0-vm--103--disk--1  212G  129G   74G  64% /