cassandrasecondary-indexescassandra-2.2

Cassandra SELECT on secondary index doesn't return row


I am dealing with a puzzling behaviour when doing SELECTs on Cassandra 2.2.3. I have 4 nodes in the ring, and I create the following keyspace, table and index.

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);

Then I insert some rows on the table. Some of them have empty sets. I perform this query through the default CQL client and get the row I am expecting:

SELECT * FROM my_table WHERE code = 'test';

Then I run some tests which are outside my control. I don't know what they do but I expect they read and possibly insert/update/delete some rows. I'm sure they don't delete or change any of the settings in the index, table or keyspace.

After the tests, I log in again through the default CQL client and run the following queries.

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';

The first one doesn't return anything. The second one returns all the rows, including the one with code = 'test'. The third one returns the expected row that the first query couldn't retrieve.

The only difference that I can see between this row and others is that it is one of the rows which contains some empty sets, as explained earlier. If I query for another of the rows that also contain some empty sets, I get the same behavior.

I would say the problem is related to the secondary index. Somehow, the operations performed during the tests leave the index in an state where it cannot see certain rows.

I'm obviously missing something. Do you have any ideas about what could cause this behavior?

Thanks in advance.

UPDATE:

I worked around the issue, but now I found the same problem somewhere else. Since the issue first happened, I found out more about the operations performed before the error: updates on specific columns that set a TTL for said columns. After some investigation I found some Jira issues which could be related to this problem:

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

However, those issues seem to have been solved on 2.0 and 2.1, and I'm using 2.2. I think these changes are included in 2.2, but I could be mistaken.


Solution

  • I opened a Jira issue and the problem was fixed on 2.1.18 and 2.2.10: https://issues.apache.org/jira/browse/CASSANDRA-13412

    I speak just from what I read in the Jira issue. I didn't test the above scenario again after the fix was implemented because by then I had moved to the 3.0 version.

    In the end though I ended up removing almost every use of secondary indices in my application, as I learned that they led to bad performance.

    The reason is that in most cases they will result in fan-out queries that will contact every node of the cluster, with the corresponding costs.

    There are still some cases where they can perform well, e.g. when you query by partition key at the same time, as no other nodes will be involved.

    But for anything else, my advice is: consider if you can remove your secondary indices and do lookups in auxiliary tables instead. You'll have the burden of maintaining the tables in sync, but performance should be better.