云扳手,使用哈希的基于时间戳的历史记录



我想保留特定表上数据库写入的完整历史记录。此表的主要用途是读取最新数据,但所有插入和更新的完全可审核性也是业务需求。这里的官方 Spanner 文档提到了模式反模式,其中之一是关于单调增加用作主键的数据。它涉及更改主键的顺序可以分散负载,还建议使用哈希、带模的分片、UUID 等。

这篇 Google Cloud 博客文章提到最好使用ShardId而不是时间戳哈希。

但请注意,使用简单哈希会使按时间戳范围查询的速度非常慢,因为检索一系列时间戳将需要全表扫描以覆盖所有哈希。相反,我们建议从时间戳生成 ShardId。

提供了示例表设置,并使用TimestampShardId进行查询。

TimestampShardId = CRC32(Timestamp) % 100
CREATE TABLE Events (
TimestampShardId INT64 NOT NULL
Timestamp TIMESTAMP NOT NULL,
event_info...
) PRIMARY KEY (TimestampShardId, Timestamp DESC)
Select * from Events
WHERE
TimestampShardId BETWEEN 0 AND 99
AND Timestamp > @lower_bound
AND Timestamp < @upper_bound;

我不明白这种TimestampShardId如何使扫描比简单的哈希更快。这两种方法似乎都需要扫描整个表格 - 任何人都可以告诉我为什么首选ShardId?例如,为了获取完整的历史记录,使用时间戳哈希作为主键的历史记录表是否会导致问题?带有 UUID 和时间戳的主键呢?

这个想法是,Cloud Spanner可以通过对TimestampShardId的每个值执行分布式联合,然后读取键以按顺序读取该分片来避免完整的事件表。

将此视为合并 N 个排序列表与执行完整排序相比的复杂性。如果 N 很小,则合并将相对有效。另一方面,当 N 接近列表中的项数时,性能会降低到完全排序。

通过使用 TimestampShardId 的不同基数,您可以在写入可伸缩性和查询性能之间进行权衡 - 更多的分片允许更多的写入并发性,但代价是在查询期间的合并步骤中处理更多数据。我们建议使用不同数量的分片对特定工作负载进行性能测试,以查看此空间中的哪个点最适合您。

最新更新