ScyllaDB 中的分区键和数据建模

Partition Keys & Data Modeling in ScyllaDB

在 Scylla 中,数据按分区键存储。如果我查询一个有很多分区键的大 table,是否相当于对 table 执行多个查询?例如,假设我有以下 table:

key1 : val1
key2 : val2
key3 : val3

其中 3 个键 (key1..3) 中的每一个都是不同的分区键。

如果我对 table 执行以下查询:

SELECT * from table.

Scylla,大概需要在 3 个不同的分区上执行此查询 3 次,因为每一行都存储在不同的分区上。这似乎效率低下,因为这意味着查询将在每个分区执行一次。假设数据被划分为 100 个分区(100 个键),查询是否需要执行 100 次才能完成? (推而广之,查询速度只会和最慢的服务器一样快?)

如果这是真的,那么从 3 个单独的 table 中查询 1 行(例如,每行具有不同的分区键)应该具有与从一个 [=29 中查询 3 行时相同的性能=] 3 三行中的每一行都有不同的分区键?换句话说,数据是建模为一个 table 还是多个 table 的一部分,并不重要。重要的是两行或多行是否共享相同的分区键?

当我们查询 3 个不同的 table 时会发生什么,如果每行都具有相同的分区键,这是否与从一个 table 中查询 3 行一样高效,其中所有行都具有相同的分区键分区键?

评估上述 3 种情况下的绩效预期的任何指导都将非常有帮助。

谢谢!

以后尽量每个问题只问一个问题。

SELECT * from table

由于无法确定确切的分区,驱动程序将选择集群中的一个节点来发送查询。该节点成为该查询的“协调器”。然后它向集群中的每个节点发送请求,并构建结果集。一旦完成,协调器 returns 将结果集返回给驱动程序。在这种特殊情况下,它必须轮询集群中的所有节点以仅找到 3 行......效率不高。

这就是为什么未绑定查询在 Cassandra/Scylla 世界中确实不是一个好主意,因为一个节点负责轮询来自所有其他节点的数据。在大集群、大数据场景下,作为协调器的节点出现变慢甚至崩溃的情况并非闻所未闻。

If this is true, then querying 1 row from 3 separate tables (e.g, where each row has a different partition key), should have identical performance

我通过阅读本文假设,分区键作为每个查询的 WHERE 子句的一部分提供。从 3 个单独的表中查询单个特定行会更快。基本上,它不需要详尽检查集群中的每个节点。驱动程序可以简单地散列三个分区键,并确切知道去哪里获取数据。如果驱动程序使用 token-aware 负载平衡策略,则在这种情况下三个查询的执行速度会更快,因为不需要单个节点充当协调器,跳过一次网络行程。

What happens when we query 3 different tables were each row has the same partition key, is this as efficient as querying 3 rows from one table where all of the rows have the same partition key?

这将执行类似于之前的场景,其中三个不同的查询将是 运行。它们都进入同一个分区这一事实应该没有太大区别,除了将使用相同的节点来提供数据。

作为额外参考,这里有一个来自 Scylla 文档的 link 到 Fault Tolerance 图表。它提供了更多关于读写操作路径的可视化细节,以及复制因子、一致性级别和多个节点的影响。

如您所述,查询 SELECT * FROM table 不是单个分区中的查询,而是 whole-table 扫描。 whole-table 扫描是“昂贵的”,因为它需要读取 table 中的所有数据(如果你 运行 它完成),但它不像你认为它可能是:

Scylla 或 Cassandra 通过查找现存分区键列表开始这样的查询 - 然后单独查询每个分区键。相反,Scylla 和 Cassandra 具有分区键的确定性顺序,so-called“令牌”顺序(您可以将分区键的“令牌”视为哈希函数)。各个服务器节点持有这些令牌的连续范围,因此扫描整个 table 是通过扫描这些连续令牌范围(也称为“vnodes”)中的每一个来实现的 - 每个令牌范围都是由有效读取数据的单个节点有效实现的从它自己的磁盘顺序。因此,您可以拥有一百万甚至十亿个分区,并且 SELECT * FROM table 读取整个 table 仍将涉及 mostly-sequential 从磁盘读取 - 而不是一百万或十亿个单独分区。

我不得不说的另一条评论是,如果您考虑只有 3 个分区,并担心将数量增加到 100,那么您误解了 Scylla(和 Cassandra)中的数据建模。其实100个分区还是太少了。您应该有 100 多个分区。越多越好。原因是如果你只有几个巨大的分区,数据将不会均匀地分布在节点和分片之间(CPUs)。如果你只有 3 个分区和 100 个 CPU,因为每个分区都属于一个 CPU(在 Cassandra 中,一个服务器),你将只有 100 个 CPU 中的 3 个正在工作,这当然不是一个好主意。拥有一百万个分区比只有 3 个要好得多。