我使用clickhouse作为我的项目基础数据库及其 MergeTree
表工程。我想用 Custom Partitioning Key
功能,我创建了如下表:
CREATE TABLE MyTable
(
UserID UUID,
ResourceID UUID,
TimeStamp DateTime,
Usage Int64,
Version UInt32
)
ENGINE = ReplacingMergeTree(Version)
PARTITION BY toYYYYMM(TimeStamp)
ORDER BY (toYYYYMMDD(TimeStamp), UserID, ResourceID , TimeStamp)
分区密钥无效 toYYYYMM(TimeStamp)
这意味着clickhouse会按月分离数据。与此同时,我用 toYYYYMMDD(TimeStamp)
作为主索引中的第一列。我摄取了一年的数据(每月大约3000-4000万行)进行测试。
当我使用 TimeStamp
过滤条件,我得到一些混乱的结果。以下是我的sql:
select count(*) from MyTable WHERE
TimeStamp>=toDateTime('2019-01-30 00:00:00')
and
TimeStamp<toDateTime('2019-02-04 00:00:00')
它处理了7562万行(1月和2月的全部数据)!这意味着查询条件可以命中正确的分区,但缺少主键。但是如果手动转换时间戳,如下所示:
select count(*) from MyTable WHERE
toYYYYMMDD(TimeStamp)>=toYYYYMMDD(toDateTime('2019-01-30 00:00:00'))
and
toYYYYMMDD(TimeStamp)<toYYYYMMDD(toDateTime('2019-02-04 00:00:00'))
然后它只处理了700万行(5-6天的数据)。这意味着查询条件命中主键。
让我困惑的是,既然clickhouse可以在没有转换时间戳的情况下命中正确的分区,为什么它也不能自动命中主键呢?我真的需要手动转换时间戳吗?
1条答案
按热度按时间4xrmg8kj1#
表定义将过多的信息添加到用于将索引定义到行数据的顺序中。我猜,当您将筛选条件指定为todatetime('2019-01-30 00:00:00')时,clickhouse不能使用索引的第一部分。结果,它读了整个部分。请尝试按以下方式定义表:
在这种情况下,两个查询的性能应该相同。在这两种情况下,它可能比过滤器与索引的第一列完全匹配的最快查询慢一点,但比不匹配的查询快一点。
有关正在进行的操作的更多信息,请查看clickhouse日志,它位于/var/log/clickhouse-server/clickhouse-server.log中。您将看到一些消息,告诉您clickhouse实际读取了多少数据来进行计数。下面是一个例子。
在这种情况下,我们可以看到它选择了相对较少的标记(即数据颗粒)来读取。这使您了解主键索引的工作效率。