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

Oleg Anastasyev commented on CASSANDRA-6477:
--------------------------------------------

Sorry for a slight delay. Here are my throughts, hope you'll find them useful:

1. Composite indexes are the most useful feature of GI. Majority of our GI are 
composite, some with different clustering order defined. And this is not much 
more work to implement composite indexes by the way. Composite partition keys 
on GI CF are also used to split otherwise wide partitions of global index with 
popular and frequently changing values. These otherwise wide partitions suffer 
from too much range tombstones (obvously on modification of indexed value a 
range tombstone is generated because on .

2. As I can see from changes to CQL syntax and CFMetaData.java, compaction and 
compression props are copied from base CF to global index CF. GI CFs could have 
row sizes, update behaviour, reads and writes very different from its base CF, 
so specifying compaction, compression properties as well as other available in 
CREATE TABLE WITH clause could be useful. 

The syntax for GI with composite keys then could be eg:
{code}
CREATE GLOBAL INDEX indexname ON baseCF( (partk1,partk2),clustkey1,... ) 
DENORMALIZED ... WITH <all the with properties of normal table>
{code}
( I'd also suggest to replace the keyword "DENORMALIZED" with something more 
familiar to SQL ppl, like "INCLUDE", eg in 
https://msdn.microsoft.com/en-us/library/ms190806.aspx )

3. I am not sure forbidding to create global index on the column with existing 
2i is good idea. We use 2 modes for global index: Right after global index is 
created only writes to the new index are activated. No reads from it are 
allowed while the base CF dataset is scanned and its data copied to the global 
index. If there are another global or 2i available on the same columns which 
could be used for reads - they are used. After a build is complete, operator 
can enable the just built index for read using ALTER GLOBAL INDEX ENABLE 
statement, and disable old indexes. This makes transition to GI and changing 
the structure of GI smoother from operational perspective. In case of something 
go wrong, operator just disables new and re-enables old indexes in no-time. 
Applying the same write-only/read-write mode switch here could make ppl 
transition from 2i to GI easier. This feature also makes on-the-run rebuild of 
GI possible, which could be useful until all bugs with inconsistent global 
index updates would be fixed. 

4. The base CF old data scan to fill data into new global index consistently 
with base CF is another tricky process, to which I came after several trials 
and errors. It has no external dependencies and most work is performed locally 
on C* nodes. You may find it useful as well.
It breaks into 6 stages:
        1. First of all a new empty table to hold index data is created.
        2. Index writes are started on all nodes. So new modifications start to 
fill the index. At this moment new index is disabled for reading.
        3. C* nodes launch the primary range repair procedure on the base table 
to make sure all replicas of it are the same.
        4. C* nodes each scan their primary ranges of the data locally in the 
base table and fill index memtable and preparing data to stream to other nodes 
in parallel.
        5. Then they stream necessary data to other nodes, according to 
partitioning schema and replica count.
        6. When streaming completes, index is ready and enabled for clients to 
read as a final step either automatically or by operator command.

Some smaller issues I found in the Carl's branch are:

1. Not sure, how base table schema evolution is supported on fully denormalized 
global index. If column is added to base table it must be added to GI. Same 
with drop of column in base table, drop of the base table itself.
2. It looks like due to order of schema modifications in 
CreateGlobalIndexStatement.announceMigration (define global index to base CF 
and then create the GI CF itself) and DropGlobalIndex (drop GI CF and then 
deregister it from base table) there will be mutations to unknown CF, when 
schema modifications not applied fully to all nodes of cluster. I'd suggest 
creating GI CF first, then register it as global index in base table metadata.
3. Not sure, is delete of the row from base table implemented right. It seems 
like current implemenmtation of MutationUnit.oldValueIfUpdated interprets 
deletion as no-change to global index.
4. StorageProxy.mutateAtomic in case of concurrent modifications of the base 
row will produce inconsistent records to global index, but as I understood this 
is to be resolved later.


> Global indexes
> --------------
>
>                 Key: CASSANDRA-6477
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-6477
>             Project: Cassandra
>          Issue Type: New Feature
>          Components: API, Core
>            Reporter: Jonathan Ellis
>            Assignee: Carl Yeksigian
>              Labels: cql
>             Fix For: 3.0
>
>
> Local indexes are suitable for low-cardinality data, where spreading the 
> index across the cluster is a Good Thing.  However, for high-cardinality 
> data, local indexes require querying most nodes in the cluster even if only a 
> handful of rows is returned.



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

Reply via email to