
papa
09.08.2017
10:12:30
еще можно nested (keys: array (string), values array(string))

Alex
09.08.2017
10:13:08
а массивы нельзя в MergeTree :(

Alan
09.08.2017
18:35:02
всем привет, подскажите как имея таблицу hits_all от logs api с date и datetime у каждого хита посчитать среднюю продолжительность нахождения на сайте? принцип, ссылки, или может запрос есть под рукой - все пригодится

Andrew
09.08.2017
18:39:33
@miptgirl
Будет непросто. Может лучше сразу скачать вместо хитов визиты?

Google

Alan
09.08.2017
18:46:24

Alexey
09.08.2017
19:02:21

Tima
09.08.2017
19:04:48


Alexey
09.08.2017
19:05:27
По поводу, почему данные могут занимать меньше в ORC формате. Это может зависить от настроек сжатия. Если при использовании ORC, сжатие более сильное, чем lz4 - займёт меньше. Чтобы включить в ClickHouse более сильное сжатие, можно поменять настройку compression в config,xml, например, так:
<compression>
<case>
<method>zstd</method>
</case>
</compression>
- включит сжатие zstd при всех фоновых мержах.
Вторая возможная причина - изменение самой структуры данных.
450 таблиц - это плохо.
450 таблиц типа MergeTree будут работать, а при использовании ReplicatedMergeTree, на таком количестве могут постепенно начаться всякие проблемы. Дело в том, что каждая таблица типа ReplicatedMergeTree - довольно тяжёлый объект.
Полностью динамические свойства можно хранить в Nested(name String, value String). Но если атрибутов всё-таки не слишком много (сотни), то можно держать отдельные столбцы для каждого. Не стоит беспокоиться, если значения будут сильно разреженными.


Vladimir
09.08.2017
19:09:23
А есть ли разница в части загрузки КХ и ЗК
1 таблица из 100 реплицируемых шард
или
100 таблиц с одной реплицируемой шардой
?

Alexey
09.08.2017
19:11:01

Vladimir
09.08.2017
19:15:49
Вопрос такой что есть 200 серверов.
Я могу сделать 100 таблиц каждая по 2 реплики и 1 шарде
А могу сделать 1 таблицу со 100 шардами и 2 репликами.
(понятно что это просто по 1 локальной таблице в итоге на сервере)
так вот будет ли разной нагрузка на КХ и ЗК или нет

Alexey
09.08.2017
19:17:11
Тоже не совсем понятно. Дело в том, что нет понятия "шарда для таблицы". Таблицы на разных шардах живут независимо и работают вместе лишь при запросах из Distributed таблицы.

Vladimir
09.08.2017
19:18:08
понял, значит ответ на мой некорректный вопрос - нагрузка будет одинакова тк физичести это будет все теже 100 таблиц с 2 репликами в обоих случаях

Alexey
09.08.2017
19:24:39
Да.

Google

Alexander
09.08.2017
21:29:44
А я правильно понимаю, что в запакованном блоке mark может указывать на любую позицию по сути. т.е. mark in compressed file вовсе не возрастающий? так как архиватор может перемешать блоки? Я пока просто блоки пытаюсь выставить последовательно (не part)

Alexey
09.08.2017
21:34:40
Засечки в индексе строго возрастают.
Mark представляет собой пару:
- смещение в файле до начала сжатого фрейма, где есть искомые данные;
- смещение в разжатом фрейме до данных.

Alexander
09.08.2017
21:37:30
Но mark.in_compressed не может служить идентификатором очередности? Я просто ожидал, что он расти будет. Что-то не так понял видимо.

Alexey
09.08.2017
21:41:11
Для разных столбцов в засечках разные смещения.
Если рассматривать один столбец:
- в нём у каждой следующей засечки смещение в сжатом файле больше или равно предыдущему. А пара (смещение в сжатом файле, смещение в разжатом фрейме) лексикографически больше.
Для разных кусков данных (parts) будут разные файлы, и смещения в них никак не связаны.
При параллельной обработке запроса, даже один файл может читаться сразу в разных местах.

Alexander
09.08.2017
21:43:17
Ок, спасибо, я понял что оно все же должно расти, попытаюсь понять почему не вижу этого. Я выбрал только по одной нитке вроде.

Alexey
09.08.2017
21:43:58
Да, [ 13 ] - это номер потока. Он один. В остальном я не понял, что вы вывели.

Alexander
09.08.2017
21:45:29
Я в seekToMark вывел mark.offset_in_compressed. остальные строчки - не важно. Надо наверное ещё индекс марка посмотреть сейчас, может в нём дело.
Ага, спасибо, немного понятнее, сами индексы Марков не последовательно.

Alexey
09.08.2017
21:51:23
mark.offset_in_uncompressed
- для мелких столбцов часто равен нулю за счёт "выравнивания сжатых блоков по засечкам". В остальном никакого утверждения о монотонности нет.
Пример, что такое засечка.
Все несжатые данные файла:
[-------------------------------]
^ ^
индекс указывает сюда.
Данные сжимаются.
Вот такие получились фреймы для сжатия:
[---------][---------][---------]
^ ^
Они сжались как-то так:
[~~~][~~~~~~][~~]
^ ^
offset_in_compressed_file будет указывать сюда - на начала сжатых фреймов в файле.
[---------]
^
[---------]
^
А offset_in_decompressed_block будет указывать сюда - на позицию данных внутри фрейма.

Alexander
09.08.2017
21:53:11
Я извиняюсь, опечатался тут в чате. Я в compressed смотрел. И его имел ввиду, да, uncompressed 0
Могут две засечки указывать на один фрейм?
Например одинаковые данные и упаковалось в один блок. Или будет два блока? Те три блока выше упаковаться в два.

Alexey
09.08.2017
21:57:05
Могут. Есть минимальный размер сжатого фрейма - 64 KB и максимальный - 1 MB.
Допустим, столбец имеет тип UInt8, index_granularity = 8192. Тогда в один сжатый фрейм попадут целых 8 засечек.

Alexander
09.08.2017
21:58:48
Но они будут иметь разный uncompressed. А могут ли непоследовательные marks указывать на один in_compressed? Если могут - то это все усложняет.

Alexey
09.08.2017
22:01:52
> Но они будут иметь разный uncompressed.
> А могут ли непоследовательные marks указывать на один in_compressed?
Не совсем корректный вопрос.
Могут ли marks для одного part, для одного столбца быть не монотонными, если рассматривать лексикографическое сравнение - нет.
Попробуйте посмотреть .mrk файлы напрямую. Эти файлы не сжаты. Там подряд уложены пары offset_in_compressed_file, offset_in_decompressed_block. И то, и другое - это UInt64, little endian.

Alexander
09.08.2017
22:05:49
Ага. Спасибо что ответили, так как вникнуть во внутренности быстро и легко пока не удалось.

Павел Максимов
10.08.2017
05:51:01

Александр
10.08.2017
06:11:02
Уберите из запроса format tsv, надо что бы остался только create database test1

Google

Alex
10.08.2017
07:37:55


Павел Максимов
10.08.2017
07:59:56
@FacedSID спасибо

f1yegor
10.08.2017
08:46:35
привет. как сделать SELECT arrayJoin([1, 2, 3] AS src) AS dst, 'Hello', src но чтобы если массив пустой - строчка не пропадала, а было как при left join?

Александр
10.08.2017
08:59:41
Можно попробовать так, но в таком случае на пустых массивах будет одна строчка с empty, но на этот случай можно сделать проверку далее в запросе

papa
10.08.2017
09:03:34
select 'hello',z from system.one left array join range(rand()%3) as z

f1yegor
10.08.2017
09:06:05
спасибо, отлично

Oleg
10.08.2017
10:52:01
Добрый день! Подскажите, можно ли как-то выбрать последние вставленные N строк? Если делать order by time|date DESC, то он фуллскан делает, сортировку точнее на весь набор данных, это долго понятно

Roman
10.08.2017
10:57:39
а если лимит по дате поставить, к примеру, за последний день/час, тогда скан будет только по последним партам.
как я понимаю, ch читает данные с диска (и других нод) параллельно из многих мест сразу. с учетом этого понять что из прочитанного - последние N строк, но без сортировки, довольно затруднительно.

Vladimir
10.08.2017
19:20:49

Alexey
10.08.2017
19:25:59

Vladimir
10.08.2017
19:28:14
Я имею ввиду датасорс для данной таблицы

Alexey
10.08.2017
19:28:58
Таблицы типа Dictionary можно создать двумя способами:
1. По отдельности, с помощью CREATE TABLE ... ENGINE = Dictionary(dict_name).
2. Таблицы для всех словарей сразу. Это работает с помощью создания специальной базы данных. CREATE DATABASE name ENGINE = Dictionary
Это самый простой способ, так как никаких аргументов указывать не нужно.
Сами словари должны быть заранее объявлены в конфигурационных файлах, как обычно.

Vladimir
10.08.2017
19:29:28
Огромное спасибо!

f1yegor
10.08.2017
23:23:59
+1

Google

Дмитрий
11.08.2017
06:25:37
Всем привет. А кто-то вливал в обычную таблицу с MergeTree через JDBC драйвер больше 2кк строчек в секунду? Я конечно еще не до конца разобрался куда уперся в моем случае, пока гоняю тесты и подкручиваю связку в разных местах, но хочется понять, это потолок, или можно выше прыгнуть?
Лью через RowBinaryStream, косяки с лонгами обошел, сериализацию и отправку стрингов на своей стороне подкрутил, и на первый взгляд проблем больше нет.
Строчки по 66 байт, но на локалхосте результаты примерно такие же, поэтому кажется что это не диск и не сеть, чуть позже проверю точнее.

Eugene
11.08.2017
06:34:38
Всем привет. Подскажите, можно ли сделать materialized-вьюху, которая будет аккумулировать в себе данные двух таблиц по одному и тому же where ?

Admin
ERROR: S client not available

Виктор
11.08.2017
07:20:32
@neiwick Порядок данных важен? Если нет то пробовал ли ты разбить данные на куски и пихать в несколько потоков? Мы так у себя справились с задержками. В безопасные 190 потоков льем кучу данных

Дмитрий
11.08.2017
07:25:52
Абсолютно не важен, спасибо! При таком способе заливки получается утилизировать сеть?

Kirill
11.08.2017
09:06:43

Eugene
11.08.2017
09:08:47

Kirill
11.08.2017
09:09:55
материализованное вью не читают данные из таблиц
там создается отдельная таблица в которую пишутся данные к которым применен запрос указанный во вью

Eugene
11.08.2017
09:32:31

M
11.08.2017
09:32:59
А через UNION данные не заходят?


Дмитрий
11.08.2017
09:52:09
Всем привет!
Скажите, кто-то работал с КХ из go?
Наткнулся на вроде как баг, не пойму чей он. Вроде на КХ запросы выполняются, поэтому подозреваю, что это на его стороне.
Пытаюсь сделать мультилайн-инсерт (4 строки по 5 полей).
if transaction, err = db.ClickHouseClient.Begin(); err != nil {
log.Error(fmt.Errorf("Can't start transaction: %v", err))
return
}
if stmt, err = transaction.Prepare(sql); err != nil {
log.Error(fmt.Errorf("Can't prepare statment (%s): %v", sql, err))
transaction.Rollback()
return
}
if _, err = stmt.Exec(data...); err != nil {
log.Error(fmt.Errorf("Can't execute statment (%s) with data (%v): %v", sql, data, err))
transaction.Rollback()
return
}
если data - это []interface{} из 20 элементов, то получаю ответ, что ожидается 5
[clickhouse][begin] tx=false, data=false
[clickhouse][prepare] INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)
[clickhouse][send query] INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES
[clickhouse][rollback] tx=true, data=true
[clickhouse]-> ping
2017/08/11 12:05:56 [err] Can't execute statment (INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)) with data ([WXOsS2b6HKVar5J3 10 h_view RU74Челябинск 2017-08-11 12:05:44.144234036 +0300 +03 WXOsS2b6HKVar5J3 1 h_view RU74Челябинск 2017-08-11 12:05:45.216646508 +0300 +03 WXOsS2b6HKVar5J3 10 h_view RU74Челябинск 2017-08-11 12:05:46.242552452 +0300 +03 WXOsS2b6HKVar5J3 1 h_view RU74Челябинск 2017-08-11 12:05:47.160877142 +0300 +03]): block: expected 5 arguments (columns: uid, pid, event, geodata, created_at), got 20
[clickhouse][stmt] close
а если передаю не правильное количество аргументов (слайс слайсов интерфейсов 5х4), то он уже ожидает 20, а получил 4
`
Т.е. стейтмент не меняется, но КХ ожидает то 5, то 20
Can't execute statment (INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)) with data ([[WXOsS2b6HKVar5J3 1 h_view RU74Челябинск 2017-08-11 11:41:16.08478083 +0300 +03] [WXOsS2b6HKVar5J3 10 h_view RU74Челябинск 2017-08-11 11:41:17.096437511 +0300 +03] [WXOsS2b6HKVar5J3 1 h_view RU74Челябинск 2017-08-11 11:41:17.983410114 +0300 +03] [WXOsS2b6HKVar5J3 10 h_view RU74Челябинск 2017-08-11 11:41:18.864966974 +0300 +03]]): sql: expected 20 arguments, got 4
разные куски кода проверяют разные вещи
block: expected 5 arguments, got 20
sql: expected 20 arguments, got 4
и вот это go проверяет или КХ?


Ivan
11.08.2017
10:00:39
Привет! Заметил странное поведение. Когда заливаю данные через Distributed (insert into some_distibuted select * from other_table), одним большим батчем, то происходит OutOfMemory. Distributed связан с SummingMergeTree. Если заливать по частям, то происходит некоректный подсчет Summing поля, если не дождаться пока Distributed не закончит рассылку по всем нодам и начать заливку следующего батча. Из документации не понятно данное поведение (и OutOfMemory и неправильный подсчет Summing поля), поэтому предполагаю что это бага


Kirill
11.08.2017
10:00:45
это Go проверяет, сейчас посмотрю
Всем привет!
Скажите, кто-то работал с КХ из go?
Наткнулся на вроде как баг, не пойму чей он. Вроде на КХ запросы выполняются, поэтому подозреваю, что это на его стороне.
Пытаюсь сделать мультилайн-инсерт (4 строки по 5 полей).
if transaction, err = db.ClickHouseClient.Begin(); err != nil {
log.Error(fmt.Errorf("Can't start transaction: %v", err))
return
}
if stmt, err = transaction.Prepare(sql); err != nil {
log.Error(fmt.Errorf("Can't prepare statment (%s): %v", sql, err))
transaction.Rollback()
return
}
if _, err = stmt.Exec(data...); err != nil {
log.Error(fmt.Errorf("Can't execute statment (%s) with data (%v): %v", sql, data, err))
transaction.Rollback()
return
}
если data - это []interface{} из 20 элементов, то получаю ответ, что ожидается 5
[clickhouse][begin] tx=false, data=false
[clickhouse][prepare] INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)
[clickhouse][send query] INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES
[clickhouse][rollback] tx=true, data=true
[clickhouse]-> ping
2017/08/11 12:05:56 [err] Can't execute statment (INSERT INTO events (uid, pid, event, geodata, created_at) FORMAT VALUES (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)) with data ([WXOsS2b6HKVar5J3 10 h_view RU74Челябинск 2017-08-11 12:05:44.144234036 +0300 +03 WXOsS2b6HKVar5J3 1 h_view RU74Челябинск 2017-08-11 12:05:45.216646508 +0300 +03 WXOsS2b6HKVar5J3 10 h_view RU74Челябинск 2017-08-11 12:05:46.242552452 +0300 +03 WXOsS2b6HKVar5J3 1 h_view RU74Челябинск 2017-08-11 12:05:47.160877142 +0300 +03]): block: expected 5 arguments (columns: uid, pid, event, geodata, created_at), got 20
[clickhouse][stmt] close
а если передаю не правильное количество аргументов (слайс слайсов интерфейсов 5х4), то он уже ожидает 20, а получил 4
`
Как говорил Джобс: "Вы держите его неправильно"
делайте
INSERT INTO events VALUES (?, ?, ?, ?, ?)
Далее в цикле забиваете данные через execute (у вас получится 4 итерации по 5 значений) и Commit который отошлет блок данных на сервер


Дмитрий
11.08.2017
10:08:06
а как же рекомендация из мануала при использовании репликации вставлять данные пачками не чаще раза в секунду? 4 инсерта по одной строке - это ж не 1 инсерт 4х строк

Google

Kirill
11.08.2017
10:09:36
нет, он копит данные в буфере, рулится настройкой block_size, если "строк" больше бъет на блоки и отправляет до финального commit, commit зафаксирует все данные которые остались в буфере

Дмитрий
11.08.2017
10:15:25
иными словами: на стороне КХ в пределах одной транции 1 инсерт N строк и N инсертов по 1 строке - это одно и то же. Я верно понял?

Kirill
11.08.2017
10:17:53
нет, это все рулится на стороне драйвера, в большинстве случаев (до установленноего размера block_size) данные на сервер передадутся 1-м блоком в котором будет n-е количество строк

Дмитрий
11.08.2017
10:20:13
надо поснифить трафик

Kirill
11.08.2017
10:21:14
зачем ?

Дмитрий
11.08.2017
10:23:23
потому что если драйвер отправит одним блоком insert();insert();insert() а не insert(),(),() это будет не то. На сколько я знаю.

Kirill
11.08.2017
10:24:58
он не отправит
insert (), (), ()
там данные не в текстовом формате передаются

Дмитрий
11.08.2017
10:26:35
Оо... Тогда тем более надо )

Kirill
11.08.2017
10:29:53
Если вам интересно что там я могу рассказать и сэкономить вам время ;)

Дмитрий
11.08.2017
11:38:17
С удовольствием послущаю! ))

Lex
11.08.2017
11:52:34
+1

Kirill
11.08.2017
12:04:47
Если гошный драйвер используется через стандартный интерфейс Го, то при вызове Begin не создается транзакция, просто соединение закрепляется за стейтментом, при Prepare запрос "обрезается" до VALUES и отправляется на сервер, сервер передает метаинформацию о колонках которые он ожидает, Execute пишет в буферы колонок которые при Commit или при приделе размера блока (в строках) сливаются в один бинарный блок данных и отправляются на сервер, Commit отправляет данные из беферов, если там еще что-то осталось и шлет "пустой" блок данных чтоб сообщить серверу что все данные отправлены