我有一个cassandra Column Family,或具有以下架构的CQL表:
CREATE TABLE user_actions (
company_id varchar,
employee_id varchar,
inserted_at timeuuid,
action_type varchar,
PRIMARY KEY ((company_id, employee_id), inserted_at)
) WITH CLUSTERING ORDER BY (inserted_at DESC);
基本上是由公司ID和员工ID组成的复合分区键,以及表示插入时间的聚类列,用于按反向时间顺序排列列(最新操作位于开头这一行。
这是插件的样子:
INSERT INTO user_actions (company_id, employee_id, inserted_at, action_type)
VALUES ('acme', 'xyz', now(), 'started_project')
USING TTL 1209600; // two weeks
这里没什么特别的,除了TTL定于两周后到期。
读取路径也很简单 - 我们总是想要最新的100个动作,所以看起来像这样:
SELECT action_type FROM user_actions
WHERE company_id = 'acme' and employee_id = 'xyz'
LIMIT 100;
问题:我希望由于我们按逆时间顺序排序,并且TTL在插入时总是相同的秒数 - 这样的查询不应该扫描任何墓碑 - 所有"死&#34 ;列位于行的尾部,而不是头部。但实际上,我们在日志中会看到以下格式的许多警告:
WARN [ReadStage:60452] 2014-09-08 09:48:51,259 SliceQueryFilter.java (line 225) Read 40 live and 1164 tombstoned cells in profiles.user_actions (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=1410169639669000, localDeletion=1410169639}
并且在极少数情况下,墓碑号足够大以完全中止查询。 既然我经常提到这种类型的架构设计,我想知道我在这里做错了吗?
答案 0 :(得分:1)
您的SELECT语句没有给出明确的排序顺序,因此默认为ASC(即使您的集群顺序是DESC)。
因此,如果您将查询更改为:
SELECT action_type FROM user_actions
WHERE company_id = 'acme' and employee_id = 'xyz'
ORDER BY inserted_at DESC
LIMIT 100;
你应该没事
答案 1 :(得分:0)
也许数据再次出现,因为节点失败并且gc_grace_seconds已经过期,节点返回到集群中,并且Cassandra无法重播/修复更新,因为墓碑在gc_grace_seconds之后消失了:http://www.datastax.com/documentation/cassandra/2.1/cassandra/dml/dml_about_deletes_c.html
2.1增量修复听起来可能适合您:http://www.datastax.com/documentation/cassandra/2.1/cassandra/operations/ops_repair_nodes_c.html