Samuel Klock created CASSANDRA-8550:
---------------------------------------

             Summary: Internal pagination in CQL3 index queries creating 
substantial overhead
                 Key: CASSANDRA-8550
                 URL: https://issues.apache.org/jira/browse/CASSANDRA-8550
             Project: Cassandra
          Issue Type: Bug
          Components: Core
            Reporter: Samuel Klock


While benchmarking CQL3 secondary indexes in 2.1.2, we've noticed substantial 
performance degradation as the volume of indexed data increases.  In trying to 
figure out what's going on, we found that a major factor contributing to this 
degradation appears to be logic in 
{{o.a.c.db.index.composites.CompositesSearcher}} used to paginate scans of 
index tables.  In particular, in the use cases we've explored, this short 
algorithm used to select a page size appears to be the culprit:

{code:java}
            private int meanColumns = 
Math.max(index.getIndexCfs().getMeanColumns(), 1);
            // We shouldn't fetch only 1 row as this provides buggy paging in 
case the first row doesn't satisfy all clauses
            private int rowsPerQuery = Math.max(Math.min(filter.maxRows(), 
filter.maxColumns() / meanColumns), 2);
{code}

In indexes where the cardinality doesn't scale linearly with the volume of data 
indexed, it seems likely that the value of {{meanColumns}} will steadily rise 
in write-heavy workloads.  In the cases we've explored, {{filter.maxColumns()}} 
returns a small enough number (related to the lesser of the native-protocol 
page size or the user-specified limit for the query) that, after 
{{meanColumns}} reaches a few thousand, {{rowsPerQuery}} (the page size) is 
consistently set to 2.

The resulting overhead is severe.  In our environment, if we fix 
{{rowsPerQuery}} to some reasonably large constant (e.g., 5,000), queries that 
with the existing logic would require over two minutes to complete can run in 
under ten seconds.

Using a constant clearly seems like the wrong answer.  But the overhead the 
existing algorithm seems to introduce suggests that it isn't the right answer 
either.  An intuitive solution might be to use the minimum of 
{{filter.maxRows()}} and {{filter.maxColumns()}} (or 2 if both of those are 1), 
but it's not immediately clear that there aren't safety considerations the 
algorithm is attempting to account for that this strategy does not.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to