我看了这篇文章https://cloud.google.com/blog/products/gcp/sharding-of-timestamp-ordered-data-in-cloud-spanner 并创建了一个类似的模式,只是没有companyid:
CREATE TABLE Foo (
random_id STRING(22) NOT NULL,
shard_id INT64 NOT NULL,
timestamp_order TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
) PRIMARY KEY(random_id);
CREATE INDEX OrderIndex ON Foo(shard_id, timestamp_order);
shard\u id是0到49之间的随机数。然后我对它进行了一系列的筛选:
1: SELECT * FROM Foo@{FORCE_INDEX=OrderIndex} where shard_id=0 order by timestamp_order limit 1;
# this correctly scans 1 row
2: SELECT * FROM Foo@{FORCE_INDEX=OrderIndex} where shard_id<1 order by timestamp_order limit 1;
# this scans 192 rows
3: SELECT * FROM Foo@{FORCE_INDEX=OrderIndex} where shard_id BETWEEEN 1 AND 1 order by timestamp_order limit 1;
# this scans 185 rows
4: SELECT * FROM Foo@{FORCE_INDEX=OrderIndex} where shard_id BETWEEN 0 AND 1 order by timestamp_order limit 1;
# this scans 377 rows
我以为会这样:
Query #2 should scan 1 row
Query #3 should scan 1 row
Query #4 should scan 2 rows.
问题:我做错什么了?有没有可能在扳手中有高效的时间戳顺序查询?
3条答案
按热度按时间ffvjumwh1#
我看到了关于任意限制的评论。这对于后续评论来说太长了(不允许),所以我添加了另一个答案。
对于任意限制,需要更复杂的查询才能获得最高效率。这里是一个使用过滤器“shard_id<1000”和限制x的模板。
连接的第一个端将有效地提取符合条件的shard\u id值,这与限制为1的原始查询非常相似。联接的第二方将返回到表并获取每个shard\u id的前x行,然后父级将在所有符合条件的shard\u is值中选择前x行。如果每个shard\u id有许多时间戳,那么这将是非常有效的。
avwztpqn2#
使用having min构造可以有效地执行此查询。
重写#2:
效率将来自内部子查询。它应该只为每个shard\u id扫描一行,然后从这些行中选择最小值。如果你发现不是这样的话,那么有一个提示可以迫使这种行为。
对于其他查询,只需替换内部子查询中的筛选条件。
f0brbegy3#
当您指定多个shard id(或可能产生多个shard id的表达式)时,此时的理论结果集不再按时间戳排序(而对于单个shard,则是这样),因此必须按时间戳重新排序(并且必须考虑每一行)。当您指定一个限制时,理论上的优化是从每个shard和merge中获取top n,但看起来优化不到位。
您可以在应用程序层实现这一点,方法是对每个相关的shard并行运行limit1查询并合并结果。