删除行与删除列性能
Delete rows vs Delete Columns performance
我正在为 Cassandra 2.1.3 上的时间序列应用程序创建数据模型。我们将为系统的每个用户保留 X 量的数据,我想知道针对此要求设计的最佳方法是什么。
选项 1:
在分区键中使用'bucket',这样X周期的数据就进入了同一行。像这样:
((id, bucket), timestamp) -> data
我可以一次删除一行,但要维持这个桶的概念。它还限制了我可以在 timestamp
上查询的范围,可能会导致多个查询。
选项 2:
将所有数据存储在同一行中。每列 N 次删除。
(id, timestamp) -> data
范围查询再次变得简单。但是删除很多列后性能如何?
鉴于我们计划使用 TTL 让数据过期,这两种模型中的哪一种会提供最佳性能? Option1 << Option2 的逻辑删除开销还是两种模型上每列都有一个逻辑删除?
我尽量避免把自己埋在墓碑墓地里。
我认为这将完全取决于您计划为最终选择的给定分区键拥有多少数据、您的 TTL 是什么以及您进行的查询。
我通常倾向于选项 #1,尤其是当所有写入的 TTL 都相同时。此外,如果您正在使用 LeveledCompactionStrategy 或 DataTieredCompactionStrategy,Cassandra 会很好地将来自同一分区的数据保存在同一个 SSTable 中,这将大大提高读取性能。
如果您使用选项 #2,同一分区的数据可能会分布在多个级别(如果使用 LCS)或通常只是多个 sstables,这可能会导致您从一个很多 SSTable,具体取决于查询的性质。还有热点问题,如果你有一个非常宽的分区,你可能会在其中超载特定的 cassandra 节点。
#1(您提到的)的另一个好处是您可以轻松删除整个分区,这会创建一个成本更低的单一墓碑标记。此外,如果您使用相同的 TTL,则该分区内的数据几乎会同时过期。
我确实同意,必须进行多个查询以跨多个分区进行读取有点痛苦,因为这将一些复杂性推向了应用程序端。如果不能隐式确定,您可能还需要维护一个单独的 table 来跟踪给定 ID 的存储桶。
就性能而言,您是否认为您的应用程序进行查询时可能需要读取跨分区?例如,如果您查询 'the most recent 1000 records' 并且分区通常比它宽,您可能只需要对选项 #1 进行 1 次查询。但是,如果您想要像 'give me all records' 这样的查询,选项 #2 可能更好,否则您将需要对每个存储桶进行查询。
创建上述 tables 后:
CREATE TABLE option1 (
... id bigint,
... bucket bigint,
... timestamp timestamp,
... data text,
... PRIMARY KEY ((id, bucket), timestamp)
... ) WITH default_time_to_live=10;
CREATE TABLE option2 (
... id bigint,
... timestamp timestamp,
... data text,
... PRIMARY KEY (id, timestamp)
... ) WITH default_time_to_live=10;
我插入了一个测试行:
INSERT INTO option1 (id,bucket,timestamp,data) VALUES (1,2015,'2015-03-16 11:24:00-0500','test1');
INSERT INTO option2 (id,timestamp,data) VALUES (1,'2015-03-16 11:24:00-0500','test2');
...等了 10 秒,继续跟踪查询,我看到每个 table 的墓碑计数相同。所以无论哪种方式,你都不应该太担心。
真正的问题是,如果您认为您会达到每个分区 20 亿列的限制,那么选项 #1 是安全的。如果您有大量数据,选项 #1 可能会执行得更好(因为您将无需查看与您的 bucket
不匹配的分区),但在这方面实际上任何一个都应该没问题。
tl;dr;
由于无论您选择哪个选项,性能和墓碑问题都会相似,我认为选项 #2 更好,只是因为查询方便。
我正在为 Cassandra 2.1.3 上的时间序列应用程序创建数据模型。我们将为系统的每个用户保留 X 量的数据,我想知道针对此要求设计的最佳方法是什么。
选项 1:
在分区键中使用'bucket',这样X周期的数据就进入了同一行。像这样:
((id, bucket), timestamp) -> data
我可以一次删除一行,但要维持这个桶的概念。它还限制了我可以在 timestamp
上查询的范围,可能会导致多个查询。
选项 2:
将所有数据存储在同一行中。每列 N 次删除。
(id, timestamp) -> data
范围查询再次变得简单。但是删除很多列后性能如何?
鉴于我们计划使用 TTL 让数据过期,这两种模型中的哪一种会提供最佳性能? Option1 << Option2 的逻辑删除开销还是两种模型上每列都有一个逻辑删除?
我尽量避免把自己埋在墓碑墓地里。
我认为这将完全取决于您计划为最终选择的给定分区键拥有多少数据、您的 TTL 是什么以及您进行的查询。
我通常倾向于选项 #1,尤其是当所有写入的 TTL 都相同时。此外,如果您正在使用 LeveledCompactionStrategy 或 DataTieredCompactionStrategy,Cassandra 会很好地将来自同一分区的数据保存在同一个 SSTable 中,这将大大提高读取性能。
如果您使用选项 #2,同一分区的数据可能会分布在多个级别(如果使用 LCS)或通常只是多个 sstables,这可能会导致您从一个很多 SSTable,具体取决于查询的性质。还有热点问题,如果你有一个非常宽的分区,你可能会在其中超载特定的 cassandra 节点。
#1(您提到的)的另一个好处是您可以轻松删除整个分区,这会创建一个成本更低的单一墓碑标记。此外,如果您使用相同的 TTL,则该分区内的数据几乎会同时过期。
我确实同意,必须进行多个查询以跨多个分区进行读取有点痛苦,因为这将一些复杂性推向了应用程序端。如果不能隐式确定,您可能还需要维护一个单独的 table 来跟踪给定 ID 的存储桶。
就性能而言,您是否认为您的应用程序进行查询时可能需要读取跨分区?例如,如果您查询 'the most recent 1000 records' 并且分区通常比它宽,您可能只需要对选项 #1 进行 1 次查询。但是,如果您想要像 'give me all records' 这样的查询,选项 #2 可能更好,否则您将需要对每个存储桶进行查询。
创建上述 tables 后:
CREATE TABLE option1 (
... id bigint,
... bucket bigint,
... timestamp timestamp,
... data text,
... PRIMARY KEY ((id, bucket), timestamp)
... ) WITH default_time_to_live=10;
CREATE TABLE option2 (
... id bigint,
... timestamp timestamp,
... data text,
... PRIMARY KEY (id, timestamp)
... ) WITH default_time_to_live=10;
我插入了一个测试行:
INSERT INTO option1 (id,bucket,timestamp,data) VALUES (1,2015,'2015-03-16 11:24:00-0500','test1');
INSERT INTO option2 (id,timestamp,data) VALUES (1,'2015-03-16 11:24:00-0500','test2');
...等了 10 秒,继续跟踪查询,我看到每个 table 的墓碑计数相同。所以无论哪种方式,你都不应该太担心。
真正的问题是,如果您认为您会达到每个分区 20 亿列的限制,那么选项 #1 是安全的。如果您有大量数据,选项 #1 可能会执行得更好(因为您将无需查看与您的 bucket
不匹配的分区),但在这方面实际上任何一个都应该没问题。
tl;dr;
由于无论您选择哪个选项,性能和墓碑问题都会相似,我认为选项 #2 更好,只是因为查询方便。