Como funcionam os índices secundários em Cassandra?
CREATE TABLE update_audit (
scopeid bigint,
formid bigint,
time timestamp,
record_link_id bigint,
ipaddress text,
user_zuid bigint,
value text,
PRIMARY KEY ((scopeid, formid), time)
) WITH CLUSTERING ORDER BY (time DESC)
com dois índices secundários, em que record_link_id
é uma coluna de alta cardinalidade:
CREATE INDEX update_audit_id_idx ON update_audit (record_link_id);
CREATE INDEX update_audit_user_zuid_idx ON update_audit (user_zuid);
De acordo com o meu conhecimento, a Cassandra criará duas famílias de colunas ocultas como esta.
CREATE TABLE update_audit_id_idx(
record_link_id bigint,
scopeid bigint,
formid bigint,
time timestamp
PRIMARY KEY ((record_link_id), scopeid, formid, time)
);
CREATE TABLE update_audit_user_zuid_idx(
user_zuid bigint,
scopeid bigint,
formid bigint,
time timestamp
PRIMARY KEY ((user_zuid), scopeid, formid, time)
);
Cassandra índices secundários são implementados como índices locais em vez de serem distribuídos como tabelas normais. Cada nó só armazena um índice para os dados que armazena.
considere a seguinte consulta:
select * from update_audit where scopeid=35 and formid=78005 and record_link_id=9897;
- Como esta consulta irá executar 'debaixo do capô' em Cassandra? Como é que um índice de coluna de alta cardinalidade (
- quais os critérios que serão executados em primeiro lugar, a tabela de base partition_key ou a tabela secundária partition_key? Como É que a Cassandra vai Intersectar estes dois resultados?
record_link_id
afectará o seu desempenho?
A Cassandra vai tocar em todos os nós para a consulta acima? Porquê?
2 answers
select * from update_audit where scopeid=35 and formid=78005 and record_link_id=9897;
Como a consulta acima funcionará internamente em cassandra?
Essencialmente, todos os dados para as partições scopeid=35
e formid=78005
serão devolvidos, e depois filtrados pelo índice record_link_id
. Irá procurar o item record_link_id
para 9897
, e tentar corresponder aos itens que correspondem às linhas devolvidas onde scopeid=35
e formid=78005
. A intersecção das linhas para as chaves de partição e as chaves de índice serão devolvidas.
Quão elevada é a coluna de cardinalidade (record_link_id)índice irá afetar o desempenho da consulta para a consulta acima?
Os índices de alta cardinalidade criam essencialmente uma linha para (quase) cada entrada na tabela principal. O desempenho é afetado, porque Cassandra é projetado para realizar leituras sequenciais para resultados de consulta. Uma consulta index essencialmente força Cassandra a realizar leiturasaleatórias . Como a cardinalidade de seu valor indexado aumenta, assim faz o tempo que leva para encontrar o valor questionado.
A cassandra vai tocar todos os nós para a consulta acima? Por quê?Não. Ele só deve tocar um nó que é responsável pela partição
scopeid=35
e formid=78005
. Os índices também são armazenados localmente, apenas contêm entradas que são válidas para o nó local.
Criar um índice sobre colunas de alta cardinalidade será o modelo de dados mais rápido e melhor
O problema aqui é que a abordagem não escala, e será lenta se update_audit
é um conjunto de dados grande. MVP Richard Low tem um grande artigo sobre índices secundários ( O ponto doce para a indexação Secundária de Cassandra ), e particularmente neste ponto:
Se a sua tabela fosse significativamente maior que a memória, uma consulta seria muito lenta até mesmo para devolver apenas alguns milhares de resultados. Retornar potencialmente milhões de usuários seria desastroso, mesmo que parecesse ser uma consulta eficiente.Agora, a sua abordagem de restringir primeiro por uma partição específica vai ajudar (como a sua partição certamente deve caber na memória). Mas eu sinto que a escolha mais acertada aqui seria fazer...
Na prática, isto significa que a indexação é mais útil para devolver dezenas, talvez centenas de resultados. Ter isto em mente quando você considerar usar um índice secundário.
record_link_id
Uma chave de agrupamento, em vez de depender de um índice secundário.
Editar
Vai depender da largura das fileiras. A coisa complicada sobre índices de cardinalidade extremamente baixos, é que o % das linhas retornadas é geralmente maior. Por exemplo, considere uma linha largaComo é que ter Índice de baixa cardinalidade, quando há milhões de utilizadores, escala mesmo quando fornecemos o chave primária
users
tabela. Você restringe pela chave de partição em sua consulta, mas ainda existem 10 mil linhas retornadas. Se o seu índice estiver em algo como gender
, a sua consulta terá de filtrar cerca de metade dessas linhas, o que não irá funcionar bem.
Os índices secundários tendem a funcionar best on (for lack of a better description) "middle of the road" cardinality. Usando o exemplo acima de uma tabela de linhas largas users
, um índice em country
ou state
deve ter um desempenho muito melhor do que um índice em gender
(assumindo que a maioria desses utilizadores não vivem todos no mesmo país ou estado).
Editar 20180913
Para sua resposta à primeira pergunta, " Como a consulta acima funcionará internamente em cassandra?", você sabe qual é o comportamento quando consulta com paginação?
Considere o seguinte diagrama, extraído da documentação do controlador Java (v3. 6):
Basicamente, paging fará com que a consulta se separe e retorne ao cluster para a próxima iteração de resultados. Seria menos provável um tempo-limite, mas o desempenho tenderá para baixo, proporcional ao tamanho do conjunto de resultados totais e o número de nós no cluster.TL; DR; quanto mais resultados solicitados se espalharem sobre mais nós, quanto mais tempo vai demorar.
A consulta com apenas um índice secundário também é possível na Cassandra 2.x
Seleccione * de update_audit onde gravar_ link_ ID=9897;
Mas isto tem um grande impacto na obtenção de dados, porque lê todas as partições no ambiente distribuído. Os dados obtidos por esta consulta também não são consistentes e não puderam retransmitir nele.
Sugestão:
O uso do índice secundário é considerado uma pesquisa de sujeira da vista do modelo de dados de NoSQL.
To evitar índice secundário, poderíamos criar uma nova tabela e copiar dados para ele. Uma vez que esta é uma consulta da aplicação, as tabelas são derivadas de consultas.