[ 
https://issues.apache.org/jira/browse/CASSANDRA-12915?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15898877#comment-15898877
 ] 

Alex Petrov commented on CASSANDRA-12915:
-----------------------------------------

Sure, what I'm saying is that behaviour is unnecessary to fix the problem that 
we have. SASI Range iterators are taking the shortest range.

For example, if we have records like 

|| a || b || c ||
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |

And {{b}} and {{c}} are SASI-indexed, and we want to run the query {{WHERE b = 
2 AND c = 1}}, we will get 2 iterators, one with {{2}} (for the column {{b}}) 
and the second one with {{1,2,3}} (for the column {{c}}). Now, SASI will take 
the shortest range ({{b}}) and start iterating by "rewinding" the {{c}} 
iterator to the token {{2}}. If there's no item for the token, intersection 
will be empty. 

Now, moving closer to the problem. If we had just imbalanced iterators (one 
returning 100 results and the other just 1), SASI would be able to efficiently 
intersect ranges and hit the storage to retrieve just a single row. In the case 
with __empty__ results from one of the iterators, the one you're fixing, we 
were simply using a single iterator, and had to hit the storage a 100 times 
(assuming the other iterator returns 100 results). Now, with what I propose, we 
will hit is 0 times. Same with your approach, although with a lot of complex 
logic that I can not justify, so I have asked you to clarify. The trick was 
simply to "replace" that [null 
check|https://github.com/ifesdjeen/cassandra/commit/78b1ff630536b0f48787ced74a66d702d13637ba#diff-25d7f486e2818c56d6b01aa952d459f3L146]
 with an actual iterator, to let the intersection know there's a second part, 
and it's empty. I thought it was already discussed in [this 
comment|https://issues.apache.org/jira/browse/CASSANDRA-12915?focusedCommentId=15728412&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-15728412]
 but I'm happy to re-iterate:

bq. The way RangeIterator work and how it's optimised, we're 
[picking|https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/utils/RangeIntersectionIterator.java#L234-L237]
 the "shortest" token tree and start skipping the second token tree based on 
the results retrieved from the first one. So one of the indexes will be 
iterated anyways. The second index (since it's larger) might  have to 
fetch/load roughly 10 blocks (since they might be located far from one another 
on disk), but it never has to fetch all 2M items. It'll iterate only as many 
items as the smallest index has. For example, two index queries would skip 
through (left is which index is used, right is index of the item within the 
token tree):

and 

bq. Moreover, RangeIterator already has [different optimisation 
strategies|https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/index/sasi/utils/RangeIntersectionIterator.java#L76-L78]
 based on differences in cardinality. I'd say that current benchmark shows that 
the query is slightly slower (since we have to go through around twice as much 
data on disk). But given the numbers at hand  the difference that is small and 
it's sub-millisecond, this optimisation seems not to pay the complexity that it 
brings.

That's one of the ideas behind SASI, pretty much: to be able to efficiently 
merge, iterate and skip iterators.

Looks like we're mostly on the same page. I've ran large-scale tests with a 
variant of the patch I've posted (160+GB of data), and it works exactly as 
expected.  Now, I want to simplify the patch and make sure we do not add the 
code we do not need.  

So there's no need to add additional logic to hide empty ranges, it's already 
handled. 

> SASI: Index intersection with an empty range really inefficient
> ---------------------------------------------------------------
>
>                 Key: CASSANDRA-12915
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-12915
>             Project: Cassandra
>          Issue Type: Improvement
>          Components: sasi
>            Reporter: Corentin Chary
>            Assignee: Corentin Chary
>             Fix For: 3.11.x, 4.x
>
>
> It looks like RangeIntersectionIterator.java and be pretty inefficient in 
> some cases. Let's take the following query:
> SELECT data FROM table WHERE index1 = 'foo' AND index2 = 'bar';
> In this case:
> * index1 = 'foo' will match 2 items
> * index2 = 'bar' will match ~300k items
> On my setup, the query will take ~1 sec, most of the time being spent in 
> disk.TokenTree.getTokenAt().
> if I patch RangeIntersectionIterator so that it doesn't try to do the 
> intersection (and effectively only use 'index1') the query will run in a few 
> tenth of milliseconds.
> I see multiple solutions for that:
> * Add a static thresold to avoid the use of the index for the intersection 
> when we know it will be slow. Probably when the range size factor is very 
> small and the range size is big.
> * CASSANDRA-10765



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Reply via email to