并发计数请求优化

时间:2018-02-21 16:33:37

标签: clickhouse

我有一张表格列出了建筑物内所有人的登记和结账信息。 我的目标是计算在特定时间(如每小时)在建筑物中有多少人。

这是我的表:

CREATE TABLE checkins
(
    date_in DateTime, 
    date_out DateTime, 
    age Int32, 
    sex String, 
    date_day Date MATERIALIZED toDate(date_in)
) ENGINE = MergeTree(date_day, date_in, 8192)

示例数据

INSERT INTO checkins VALUES
    (toDateTime('2018-01-01 08:30:00'), toDateTime('2018-01-01 16:30:00'), 32, 'M'), 
    (toDateTime('2018-01-01 09:30:00'), toDateTime('2018-01-01 10:30:00'), 28, 'M'), 
    (toDateTime('2018-01-01 10:15:00'), toDateTime('2018-01-01 10:45:00'), 30, 'M'),
    (toDateTime('2018-01-01 11:30:00'), toDateTime('2018-01-01 11:45:00'), 35, 'M'), 
    (toDateTime('2018-01-01 14:30:00'), toDateTime('2018-01-01 17:30:00'), 25, 'F');

我目前正在以这种方式计算建筑物内的人数:

SELECT count(*), instant
FROM 
(
    SELECT arrayJoin([toDateTime('2018-01-01 10:00:00'), toDateTime('2018-01-01 12:00:00'), toDateTime('2018-01-01 14:00:00'), toDateTime('2018-01-01 16:00:00')] AS tabinstants) AS instant
    FROM checkins 
    WHERE (date_in < instant) AND (date_out > instant)
) 
GROUP BY instant
ORDER BY instant ASC

按预期返回

┌─count()─┬─────────────instant─┐
│       2 │ 2018-01-01 10:00:00 │
│       1 │ 2018-01-01 12:00:00 │
│       1 │ 2018-01-01 14:00:00 │
│       2 │ 2018-01-01 16:00:00 │
└─────────┴─────────────────────┘

然而,这个请求似乎不具有可扩展性:它在数组和表中的行中有很多点时非常慢。我假设这是因为连接数据的大小。是否有一种机制可以更有效地计算这些数据?

第二个问题: 如果我现在想要在每个点之间拥有最大人数,我该怎么办?

e.g。 在10:00到12:00之间我最多有3个人(10:15)

┌─count()─┬─────────────instant─┐
│       3 │ 2018-01-01 10:00:00 │ 
│       1 │ 2018-01-01 12:00:00 │
│       2 │ 2018-01-01 14:00:00 │
│       2 │ 2018-01-01 16:00:00 │
└─────────┴─────────────────────┘

1 个答案:

答案 0 :(得分:0)

您可以尝试运算符timeSlots,它会生成30分钟的数组。 arrayFilter可以过滤小时数,因此您将拥有小时数。 所以你的查询将是这样的 SELECT count(*), instant FROM ( SELECT arrayJoin(arrayFilter(x -> toStartOfHour(x) = x, timeSlots(toDateTime('2018-01-01 08:00:00'), toUInt32(toDateTime('2018-01-01 20:00:00') - toDateTime('2018-01-01 08:00:00')))) AS tabinstants) AS instant FROM checkins WHERE (toStartOfHour(date_in) <= instant) AND (toStartOfHour(date_out) + 3600 > instant) ) GROUP BY instant ORDER BY instant ASC