ScyllaDB 中的分区键和数据建模



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

key1 : val1
key2 : val2
key3 : val3

其中,3个密钥(key1..3)中的每一个是不同的分区密钥。

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

SELECT * from table.

"锡拉"可能需要在3个不同的分区上执行此查询3次,因为每一行都存储在不同的分区中。这似乎效率很低,因为这意味着每个分区将执行一次查询。假设数据被划分为100个分区(100个键),那么查询是否需要执行100次才能完成?(而且,查询的速度只能和最慢的服务器一样快?)

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

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

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

谢谢!

正如您所指出的,查询SELECT * FROM table不是单个分区中的查询,而是整个表扫描。全表扫描是";昂贵的";从某种意义上说,它需要读取表中的所有数据(如果你运行它到完成),但它并不像你想象的那样效率低下:

Scylla或Cassandra不会通过查找现存分区键的列表开始这样的查询,然后分别查询其中的每一个。相反,"锡拉"和卡桑德拉对分区密钥有一个确定的顺序,即所谓的";令牌";order(您可以将分区键的"token"看作一个散列函数)。单个服务器节点拥有这些令牌的连续范围,因此扫描整个表是通过扫描这些连续令牌范围(也称为"vnodes")中的每一个来实现的,其中每一个都是由单个节点有效地从其自己的磁盘顺序读取数据来实现的。因此,您可以有一百万甚至十亿个分区,用于读取整个表的SELECT * FROM table仍然主要涉及从磁盘的顺序读取,而不是对单个分区进行一百万或十亿次查找。

我不得不说的另一句话是,如果你考虑只拥有3个分区,并担心将数量增加到100,那么你就误解了Scylla(和Cassandra)中的数据建模。事实上,拥有100个分区仍然太少。您应该有超过100个分区。越多越好。原因是,如果您只有几个巨大的分区,那么数据将不会在节点和碎片(CPU)之间分布。如果您只有3个分区和100个CPU,因为每个分区都由一个CPU(在Cassandra中,是一个服务器)所有,那么100个CPU中只有3个在工作,这当然不是一个好主意。拥有一百万个分区比只有3个要好得多。

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

SELECT * from table

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

这就是为什么在Cassandra/Scilla世界中,未绑定查询真的不是一个好主意,因为一个节点负责轮询所有其他节点的数据。在大型集群、大数据场景中,充当协调器的节点速度减慢甚至崩溃的情况并非闻所未闻。

如果这是真的,那么从3个独立的表中查询1行(例如,每行都有不同的分区键),应该具有相同的性能

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

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

这将与前面的场景类似,其中将运行三个不同的查询。事实上,它们都去了同一个分区,这应该没有太大区别,除了相同的节点将用于服务数据。

为了获得更多参考,这里有一个链接到"锡拉"文档中的容错图。它提供了更多关于读写操作路径的可视化详细信息,以及复制因素、一致性级别和多个节点的影响。

最新更新