YugabyteDB 中具有 TTL 的表的 YCQL 二级索引

YCQL Secondary indexes on tables with TTL in YugabyteDB

[用户在 YugabyteDB Community Slack 上发布的问题]

我有一个带有 TTL 和二级索引的 table,使用的是 YugabyteDB 2.9.0,当我尝试插入一行时出现以下错误:

SyntaxException: Feature Not Supported

以下是我的架构:

CREATE TABLE lists.list_table (
    item_value text,
    list_id uuid,
    created_at timestamp,
    updated_at timestamp,
    is_deleted boolean,
    valid_from timestamp,
    valid_till timestamp,
    metadata jsonb,
    PRIMARY KEY ((item_value, list_id))
) WITH default_time_to_live = 0
    AND transactions = {'enabled': 'true'};

CREATE INDEX list_created_at_idx ON lists.list_table (list_id, created_at)
WITH transactions = {'enabled': 'true'};

我们有两种类型的查询(80% 和 20% 分布):

select * from list_table where list_id= <id> and item_value = <value> 
select * from list_table where list_id= <id> and created_at>= <created_at>

我们预计每个 list_id 会有大约 1000-10000 个条目。 TTL 大约是 1 个月。

这是一个限制,目前不支持使用 TTL 从索引的 table 中事务性地过期行(即 table 和索引中的 TTL 条目的原子过期)。有几种解决方法:

a) 在YCQL中,我们也支持一致性较弱的索引。今天没有详细记录,但您可以在此处查看详细信息:https://github.com/YugaByte/yugabyte-db/issues/1696

使用这种索引变体时要指出的主要问题是错误处理(在 INSERT 失败时),即在失败时重试 INSERT 是应用程序方面的责任。如上述问题所述 << 如果 insert/update 或一批此类操作失败,则应用程序有责任重试该操作以确保索引一致。很像在 2-table 的情况下,应用程序有责任重试(如果更新到两个 tables 之间失败)以确保两个 table s 再次同步。 >>

此类索引支持 table 和索引级别的 TTL。 (建议保持不变):https://github.com/yugabyte/yugabyte-db/issues/2481#issuecomment-537177471

b)另一种解决方法是使用后台清理作业定期删除陈旧记录(而不是使用 TTL)。

c)避免使用索引,将数据存储在两个table中。一种由原始主键组织,另一种由您想要的索引列(作为主键)组织。 table 都可以有 TTL。但是,当数据添加到数据库时,应用程序方面有责任向两个 table 插入。

第一个table的PK是((list_id, item_value)),和现在的主table一样。而不是索引你会有第二个 table;第二个 table 的 PK 是 ((list_id), created_at) 并且两个 table 都有一个 TTL。应用程序必须将数据插入到两个 table 中。在第二个 table 你有一个选择: (选项 1)复制主 table 中的所有列,包括您的 JSON 列等。这使得 Q2 查找速度更快,该行具有所需的一切;但会增加您的存储要求。 (选项2):除了PK,只把item_value列存入第二个table。对于 Q2,您必须首先查找第二个 table 并获取 item_value,然后使用 list_id 和 item_value 并从主 table 中检索数据(就像索引在幕后所做的一样。

d) 另一种解决方法是,如果我们可以避免索引并选择 PK 为 ((list_id, item_value), created_at)

这不会影响 Q1 的性能,因为如果 (where list_id and item_value) 可以使用 PK 来查找行。但是如果提供 Q2 where list_id and created_at 会比较慢,因为虽然它仍然可以使用 list_id,但它必须在没有索引帮助的情况下使用 created_at 值过滤掉数据。因此,如果 Q2 确实占您查询的 20%,您可能不想扫描 1 到 10k 个项目来查找匹配行。

为了阐明选项 (c),请记住示例: 第一个table的PK是((list_id, item_value));它与您当前的主 table 相同。您将拥有第二个索引而不是索引 table;第二个 table 的 PK 将是 ((list_id), created_at)。 table 都有 TTL 应用程序必须将条目插入到两个 table 中。 在第二个 table 你有一个选择: (选项 1)复制主 table 中的所有列,包括您的 JSON 列等。这使得 Q2 查找速度更快,该行具有所需的一切;但会增加您的存储要求。 (选项2):除了Primary Key,只在第二个table中存储item_value列。对于 Q2,您必须首先查找第二个 table 并获取 item_value,然后使用 list_id 和 item_value 并从主 table 中检索数据(就像索引在幕后所做的一样)