
Vladimir
14.02.2017
12:15:39
вернёт чуть ли не одну строку

Dmitry
14.02.2017
12:15:49
ок, не суть
Возьмем обычный MergeTree и посмотрим как там лежат данные. Данные разделены на партиции (по дате) внутри партиции данные отсортированы по PK
В данном случае (CounterID, UserID, VisitID)

Google

Aleksandr
14.02.2017
12:17:09
Тут скорее вопрос в том - если у нас праймари ключ до отдельной строки. Гранулярность индекса будет нормально работать?
То есть он будет брать раз в 8192 строки проставлять некую отметку о значении первичного ключа?
Или он будет в пределах одного значения первичного ключа пытаться найти > 8192 строки?

Dmitry
14.02.2017
12:17:46
Кода мы делаем запрос по CounterID КХ надо найти место партиции где лежат эти данные и для этого используется индекс
"То есть он будет брать раз в 8192 строки проставлять некую отметку о значении первичного ключа?"
Да, имеено так

Aleksandr
14.02.2017
12:18:12

Vladimir
14.02.2017
12:18:23
А, понятно

Dmitry
14.02.2017
12:18:28
В этом и смысл разреженного индекса
В редкий случаях имеет смысл его уменьшать, но надо понимать, что на больших таблицах это существенно увеличивает объем индекса в памяти
Например для графита мы уменьшили до 4048

Vladimir
14.02.2017
12:21:31
Спасибо! Стало ясно
Кстати, а ещё такой вопрос. А зачем в доке загоняют UniqID под intHash32, а VisitID — нет
CollapsingMergeTree(EventDate, (CounterID, EventDate, intHash32(UniqID), VisitID), 8192, Sign)
Имеет ли вообще какой-то смысл в ключе хэшировать колонки? А, если они строки, их нужно под sipHash64 загонять?
Вообще в этом есть какой-то физический смысл, или это для примера так показали?

Google

Dmitry
14.02.2017
12:26:58
Возможно это врияет на размер индекса. Но тут точно не могу сказать.

Vladimir
14.02.2017
12:30:24
И ещё, зачем в доке дату включили в первичный ключ, когда данные и так партиционированы по дате?
Да ещё и после CounterID

Dmitry
14.02.2017
12:32:04
Вероятно чаще всего запросы идут с ограничением CounterID или CounterID, EventDate
т.е. это ускоряет запросы

Vladimir
14.02.2017
12:32:36
А ключ партиционирования разве не достаточно, чтобы сократить область поиска до одной даты?

Dmitry
14.02.2017
12:32:41
Партиционирование по дате, да. Но КХ склеивает партиции до месяца

Vladimir
14.02.2017
12:32:43
Зачем ещё в первичный ключ это добавлять?

Dmitry
14.02.2017
12:34:49
Соотвественно в рамках месяца нужно ещё найти нужную дату

Vladimir
14.02.2017
12:34:54
А, понятно, спасибо
Пока остаётся только вопрос, зачем в первичном ключе нужно хэшировать колонки
Интересно, это как-то связано с сэмплированием и с ключом семплирования...
Типа, как в этом примере из доки (правда там обычный MergeTree): MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
ну понятно, это нужно для перемешивания
Получается, второй параметр здесь — это просто выражение, по которому производится сэмплирование. Но для эффективности данные должны быть отсортированы по нему, а для этого нужно это же выражение включить в ключ

Dmitry
14.02.2017
12:40:15
В этом примере да. Ключ семплирования обязан быть в PK

Алина
14.02.2017
12:53:05
всем привет
возник вопрос:
если мы хотим вставвить данные так, что несколько колонок для каждой строки имеют общие данные, а остальные - различные
например,
a | [x, y, z] | b | c | [i, j]
надо вставлять 6 строк
a|x|b|c|i
a|y|b|c|i
a|z|b|c|i
a|x|b|c|j
a|y|b|c|j
a|z|b|c|j
или как?

papa
14.02.2017
12:57:38
а как вы это в обычной базе делаете?

Алина
14.02.2017
12:59:11
В какой обычной?

Vladimir
14.02.2017
12:59:56
Если у вас на месте колонок [x, y, z], [i, j] — массивы, то вам достаточно вставить
a | [x, y, z] | b | c | [i, j]

Google

Vladimir
14.02.2017
13:00:38
Вы, конечно, можете не пользоваться массивами и денормализовать данные, вставляя, как вы указали в своё примере
Всё зависит от задачи

Алина
14.02.2017
13:00:51

Vladimir
14.02.2017
13:01:04
Каждое поле в nested — это массив
с именем, грубо говоря, field_name.subfield_name

Алина
14.02.2017
13:01:45
Мы же не сможем использовать потом MergeTree

Vladimir
14.02.2017
13:02:10
?

Алина
14.02.2017
13:02:59
Поддерживается только один уровень вложенности. Столбцы вложенных структур, содержащие массивы, эквивалентны многомерным массивам, поэтому их поддержка ограничена (не поддерживается хранение таких столбцов в таблицах с движком семейства MergeTree).
https://clickhouse.yandex/reference_ru.html#Nested(Name1%20Type1,%20Name2%20Type2,%20...)

Alexey
14.02.2017
13:03:04
https://news.ycombinator.com/item?id=13643171
upvote plz.
После upvote отвечу на все вопросы в этом чате :)

Vladimir
14.02.2017
13:04:08

Anatoly
14.02.2017
13:04:22

Alex
14.02.2017
13:06:49
плюсик не в смысле комментарий с плюсиком :)

Alexey
14.02.2017
13:07:46
Не, там такая маленькая кнопочка "вверх" слева от заголовка.
А комментарии надо осмысленные писать.

Vladimir
14.02.2017
13:08:28
ну я что-то сделал
я не делал upvote, я делал add to favorite, но теперь я могу сделать unvote, поэтому, скорее всего, я всё сделал правильно
а upvote я не нашёл

Alex
14.02.2017
13:12:06
когда делаешь favorite, upvote делается автоматически, просто ещё статья добавляется в публичные "закладки" профиля

Roman
14.02.2017
13:12:21


Alexey
14.02.2017
13:14:11
всем привет
возник вопрос:
если мы хотим вставвить данные так, что несколько колонок для каждой строки имеют общие данные, а остальные - различные
например,
a | [x, y, z] | b | c | [i, j]
надо вставлять 6 строк
a|x|b|c|i
a|y|b|c|i
a|z|b|c|i
a|x|b|c|j
a|y|b|c|j
a|z|b|c|j
или как?
Есть два варианта, как сделать структуру таблицы в этом случае:
1. Писать много строк с совпадающими значениями в части столбцов.
2. Сделать у некоторых столбцов тип Array и писать в них значения в виде массивов.
Какой вариант предпочесть, зависит от того, какой смысл этих данных.
Если в первом варианте, каждая строка - это получается какой-то отдельный осмысленный факт, и по этим фактам как раз надо делать аналитику, то он предпочтительнее.
Второй вариант (с массивами) подходит, например, в том случае, если в каждой строке много разных по смыслу массивов.

Roman
14.02.2017
13:14:11

Google

Алина
14.02.2017
13:16:24
Есть два варианта, как сделать структуру таблицы в этом случае:
1. Писать много строк с совпадающими значениями в части столбцов.
2. Сделать у некоторых столбцов тип Array и писать в них значения в виде массивов.
Какой вариант предпочесть, зависит от того, какой смысл этих данных.
Если в первом варианте, каждая строка - это получается какой-то отдельный осмысленный факт, и по этим фактам как раз надо делать аналитику, то он предпочтительнее.
Второй вариант (с массивами) подходит, например, в том случае, если в каждой строке много разных по смыслу массивов.
а записывать надо в примере 6 строк, верно?


Alexey
14.02.2017
13:16:49
Для примера:
1. Есть заказы в интернет магазине, в каждом заказе много товаров.
Имеет смысл сделать таблицу, в которой каждая строка - отдельный товар, а для заказа - много строк.
2. Есть просмотры страниц на сайте. Они могут содержать несколько достижений целей. А ещё у каждого есть массив интересов пользователя, который посетил страницу.
В этом случае имеет смысл сделать одну строку на один просмотр, а дополнительные данные держать в массивах.

Алина
14.02.2017
13:20:26

Vladimir
14.02.2017
13:20:40
оооо, не похоже совсем. дизайнер — ммм... не оч
Upvote делают обычно или плюсиком, или кнопочкой пальца вверх, или надписью "upvote"


Alexey
14.02.2017
13:28:45
/** Maximum amount of errors while reading text formats (like CSV, TSV). \
* In case of error, if both values are non-zero, \
* and at least absolute or relative amount of errors is lower than corresponding value, \
* will skip until next line and continue. \
*/ \
M(SettingUInt64, input_format_allow_errors_num, 0) \
M(SettingFloat, input_format_allow_errors_ratio, 0)
Всем привет, а есть ли в CH какой-либо аналог RANK функции ?
Например в PostgreSQL и Vertica мы используем оконные функции чтоб вытащить "условно" только первый клик по его сессии
пример
SELECT * FROM (
SELECT
session_id,
price,
action_at,
RANK() OVER (PARTITION BY session_id ORDER BY action_at ASC) as rank
FROM (
VALUES (
'session_1',
0.42,
'2017-02-14 10:16:00'::timestamp
),
(
'session_dup_1',
0.84,
'2017-02-14 10:18:00'::timestamp
),
(
'session_dup_1',
0.42,
'2017-02-14 10:16:00'::timestamp
)
) _ (session_id, price, action_at)
) AS clicks WHERE clicks.rank = 1
RANK нет. Есть rowNumberInBlock, rowNumberInAllBlocks, но это совсем не то.


Kirill
14.02.2017
14:47:15
RANK нет. Есть rowNumberInBlock, rowNumberInAllBlocks, но это совсем не то.
жаль. если рассматривать runningDifference как некую альтернативу для выборки первой записи сессии, то у меня вопрос: в документации сказано следующее Считает разницу между последовательными значениями строк в блоке данных
т.е. если её использовать примерно так
CREATE TABLE diff_test
(
session_id String,
price Float64,
action_at DateTime
) ENGINE = Memory;
insert into diff_test values ('session1', 0.42, '2017-02-14 10:16:00'),
('sessiondup1', 0.84, '2017-02-14 10:18:00'),
('sessiondup1', 0.42, '2017-02-14 10:16:00'),
('session2', 0.42, '2017-02-14 10:19:00'),
('sessiondup2', 0.42, '2017-02-14 10:19:00'),
('sessiondup2', 0.42, '2017-02-14 10:19:00'),
('session2', 0.42, '2017-02-14 10:19:00'),
('session3', 0.42, '2017-02-14 10:19:00');
select * from (
select price, action_at, session_id, runningDifference(sipHash64(session_id)) as diff from (
select session_id, price, action_at from diff_test order by session_id, action_at asc
)
) where diff <> 0 order by action_at
то мы будем терять первую строку каждого блока (если результат приходит несколькими блоками) или только первую строку всего результата ?
и что вот такой запрос будет возвращать уникальные строки с началом сессии
SELECT *
FROM
(
SELECT
price,
action_at,
session_id,
runningDifference(sipHash64(session_id)) AS diff,
rowNumberInBlock() AS num
FROM
(
SELECT
session_id,
price,
action_at
FROM diff_test
ORDER BY
session_id ASC,
action_at ASC
)
)
WHERE diff <> 0 or num = 0
ORDER BY action_at ASC


Alexey
14.02.2017
15:08:52
Всем привет! Ребята, подскажите пожалуйста правильный вариант запроса. Есть таблица с полями id, name, amount, created_at. Нужно сделать запрос на сумму по amount за последнюю неделю с гранулярностью в, скажем, 3 часа.
Я делаю приблизительно вот так:
SELECT name, sum(amount) as sum, toStartOfHour(created_at) as 3Hours FROM table WHERE id = 1 AND created_at > toDateTime(toDate('2017-02-07')) GROUP BY 3Hours, name ORDER BY 3Hours FORMAT JSON
Всё правильно. Строчек для ключей с отсутствием значений не будет. У нас была идея сделать для этого какое-то нестандартное расширение типа GROUP BY ... WITH FILL, но до этого ещё не скоро дойдём.

Andrey
14.02.2017
15:09:41
Добрый вечер. Подскажите пожалуйста, есть ли возможность "сбросить" кэши ClickHouse без рестарта сервисов?


Alexey
14.02.2017
15:10:50
жаль. если рассматривать runningDifference как некую альтернативу для выборки первой записи сессии, то у меня вопрос: в документации сказано следующее Считает разницу между последовательными значениями строк в блоке данных
т.е. если её использовать примерно так
CREATE TABLE diff_test
(
session_id String,
price Float64,
action_at DateTime
) ENGINE = Memory;
insert into diff_test values ('session1', 0.42, '2017-02-14 10:16:00'),
('sessiondup1', 0.84, '2017-02-14 10:18:00'),
('sessiondup1', 0.42, '2017-02-14 10:16:00'),
('session2', 0.42, '2017-02-14 10:19:00'),
('sessiondup2', 0.42, '2017-02-14 10:19:00'),
('sessiondup2', 0.42, '2017-02-14 10:19:00'),
('session2', 0.42, '2017-02-14 10:19:00'),
('session3', 0.42, '2017-02-14 10:19:00');
select * from (
select price, action_at, session_id, runningDifference(sipHash64(session_id)) as diff from (
select session_id, price, action_at from diff_test order by session_id, action_at asc
)
) where diff <> 0 order by action_at
то мы будем терять первую строку каждого блока (если результат приходит несколькими блоками) или только первую строку всего результата ?
и что вот такой запрос будет возвращать уникальные строки с началом сессии
SELECT *
FROM
(
SELECT
price,
action_at,
session_id,
runningDifference(sipHash64(session_id)) AS diff,
rowNumberInBlock() AS num
FROM
(
SELECT
session_id,
price,
action_at
FROM diff_test
ORDER BY
session_id ASC,
action_at ASC
)
)
WHERE diff <> 0 or num = 0
ORDER BY action_at ASC
1. Для каждого блока.
2. Да. Хотя решение выглядит неудобным, с моей точки зрения.


Andrey
14.02.2017
16:07:01

Google

Dmitry
14.02.2017
16:10:13
Внутренний кеш можно выключить опцией https://clickhouse.yandex/reference_ru.html#use_uncompressed_cache
Но в массе своей играют не эти кеши , а кеши ФС
http://unix.stackexchange.com/questions/87908/how-do-you-empty-the-buffers-and-cache-on-a-linux-system

Andrey
14.02.2017
16:15:10
Спасибо

Roman
14.02.2017
18:37:38
4 человека до 400

f1yegor
14.02.2017
20:15:32
вопрос: если я считаю кардинальность с uniq() можно как-то сырой результат этого запроса сохранить, скажем мне нужны дампы HyperLogLog структур за последние дни, а я их буду объединять с последними часами чтобы получить финальные цифры?
ну то есть если вопрос конечно не бред
просто аггрегация сейчас проходит за более 100мс, хотелось бы на порядок меньше

Alexey
14.02.2017
20:17:01
Да, можно. -State комбинатор, то есть функция uniqState как раз это делает. Она выдаёт какие-то бинарные данные. Это может быть сохранено в столбец с типом данных AggregateFunction.

f1yegor
14.02.2017
20:20:08
замечательная документация https://clickhouse.yandex/reference_en.html#-State combinator вроде этот вопрос пару дней назад здесь обсуждали с примерами?
а, на русском хоть что-то
получается что внутренне функция хеширования для HLL стабильна и выделяет прилично памяти чтобы быть способной вместить любое количество элементов?

Vitaliy
14.02.2017
20:26:06
Есть приложение clickhouse-local но оно только для чтения
Если подложить подготовленный конфиг с подготовленной data_dir, то писать можно как и в обычном сервере.
cp /etc/clickhouse-server/users.xml .
clickhouse-local --config-file "/etc/clickhouse-server/config.xml" -q "SELECT * FROM system.tables"

Alexey
14.02.2017
20:27:23
> внутренне функция хеширования для HLL стабильна
Да. (Мы не будем её менять без обеспечения того, чтобы старые состояния читались)
> выделяет прилично памяти чтобы быть способной вместить любое количество элементов?
Память выделяет по мере надобности до некоторого максимального размера, при котором расчёт приближённый.

Иван
14.02.2017
20:32:50