由于历史原因,UUID 会按其后半部分排序。这对 UUIDv4 值来说没有问题,但如果 UUIDv7 列用于定义主索引,则可能会导致性能下降 (用于排序键或分区键则没有问题) 。
更具体地说,UUIDv7 值的前半部分是时间戳,后半部分是计数器。
因此,在稀疏主键索引中对 UUIDv7 进行排序时 (即取每个索引粒度的第一个值) ,实际上会按计数字段排序。
如果 UUID 是按前半部分 (时间戳) 排序的,那么在查询开始时的主键索引分析步骤中,预计可以剪枝掉除一个 part 之外所有 part 中的全部标记。
然而,如果按后半部分 (计数器) 排序,则预计所有 parts 都至少会返回一个标记,从而导致不必要的磁盘访问。
示例:
Query
CREATE TABLE tab (uuid UUID) ENGINE = MergeTree PRIMARY KEY (uuid);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);SELECT * FROM tab;
CREATE TABLE tab (uuid UUID) ENGINE = MergeTree PRIMARY KEY (UUIDv7ToDateTime(uuid));-- Or alternatively: [...] PRIMARY KEY (toStartOfHour(UUIDv7ToDateTime(uuid)));INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);SELECT * FROM tab;