辅助索引上的 Cassandra SELECT 没有 return 行

Cassandra SELECT on secondary index doesn't return row

我在 Cassandra 2.2.3 上执行 SELECT 时遇到了一个令人费解的行为。我在环中有 4 个节点,我创建了以下键空间,table 和索引。

CREATE KEYSPACE IF NOT EXISTS my_keyspace
    WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};

CREATE TABLE my_keyspace.my_table (
    id text,
    some_text text,
    code text,
    some_set set<int>,
    a_float float,
    name text,
    type int,
    a_double double,
    another_set set<int>,
    another_float float,
    yet_another_set set<text>,
    PRIMARY KEY (id, some_text, code)
) WITH read_repair_chance = 0.0
   AND dclocal_read_repair_chance = 0.1
   AND gc_grace_seconds = 864000
   AND bloom_filter_fp_chance = 0.01
   AND caching = { 'keys' : 'ALL', 'rows_per_partition' : 'NONE' }
   AND comment = ''
   AND compaction = { 'class' : 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy' }
   AND compression = { 'sstable_compression' : 'org.apache.cassandra.io.compress.LZ4Compressor' }
   AND default_time_to_live = 0
   AND speculative_retry = '99.0PERCENTILE'
   AND min_index_interval = 128
   AND max_index_interval = 2048;

CREATE INDEX idx_my_table_code ON my_keyspace.my_table (code);

然后我在 table 上插入一些行。其中一些有空集。我通过默认的 CQL 客户端执行此查询并获得我期望的行:

SELECT * FROM my_table WHERE code = 'test';

然后我 运行 一些我无法控制的测试。我不知道他们做什么,但我希望他们阅读并可能 insert/update/delete 一些行。我确定他们不会删除或更改索引、table 或键空间中的任何设置。

测试后,我通过默认的 CQL 客户端再次登录并 运行 以下查询。

SELECT * FROM my_table WHERE code = 'test';
SELECT * FROM my_table;
SELECT * FROM my_table WHERE id = 'my_id' AND some_text = 'whatever' AND code = 'test';

第一个没有 return 任何东西。 第二个 return 包含所有行,包括代码 = 'test' 的行。 第三个 return 是第一个查询无法检索到的预期行。

我能看到这一行与其他行之间的唯一区别是它是包含一些空集的行之一,如前所述。如果我查询另一行也包含一些空集,我会得到相同的行为。

我会说这个问题与二级索引有关。不知何故,测试期间执行的操作使索引处于无法看到某些行的状态。

我显然遗漏了什么。您对可能导致此行为的原因有任何想法吗?

提前致谢。

更新:

我解决了这个问题,但现在我在其他地方发现了同样的问题。由于问题首次发生,我发现了更多关于错误发生前执行的操作:更新特定列,为所述列设置 TTL。经过一些调查,我发现了一些可能与此问题相关的 Jira 问题:

https://issues.apache.org/jira/browse/CASSANDRA-6782 https://issues.apache.org/jira/browse/CASSANDRA-8206

但是,这些问题似乎在 2.0 和 2.1 上已经解决了,我正在使用 2.2。我认为这些更改包含在 2.2 中,但我可能弄错了。

主要问题是您在 Cassandra 上 运行 的查询类型。 Cassadra 数据模型是查询驱动的,tables 被重新计算以服务于查询。

表是使用定义明确的主键(分区键和集群键)创建的。 Cassandra 不适合完整 table 扫描类型的查询。

现在来回答您的问题。

  1. SELECT * FROM my_table WHERE code = 'test';

此处使用的列是 clustring 列,它是相等搜索列,它应该是分区键的一部分。 Clustring 键将出现在不同的分区中,因此如果读取一致性级别为 1,它可能会给出空结果。

  1. SELECT * FROM my_table;

Cassandra 不适合这种 table 扫描查询。在这里它将搜索所有 table 并获取所有行(查询不佳)。

  1. SELECT * FROM my_table WHERE id = 'my_id' AND some_text = 'whatever' AND code = 'test';

您在这里提到了所有内容,因此返回了正确的结果。

我打开了一个 Jira 问题,问题在 2.1.18 和 2.2.10 上得到了修复: https://issues.apache.org/jira/browse/CASSANDRA-13412

我只是根据我在 Jira 问题上看到的内容发言。修复后我没有再测试上面的场景,因为那时我已经升级到3.0版本了。

尽管我最终删除了应用程序中几乎所有二级索引的使用,因为我了解到它们会导致性能不佳。

原因是在大多数情况下,它们会导致 fan-out 查询,这些查询将联系集群的每个节点,并产生相应的成本。

在某些情况下它们仍然可以表现出色,例如当您同时按分区键查询时,因为不会涉及其他节点。

但对于其他任何事情,我的建议是:考虑是否可以删除二级索引并改为在辅助表中进行查找。您将承担保持表同步的负担,但性能应该更好。