AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 184127
Accepted
Matt Camp
Matt Camp
Asked: 2017-08-23 17:20:00 +0800 CST2017-08-23 17:20:00 +0800 CST 2017-08-23 17:20:00 +0800 CST

PERMITIR FILTRAGEM vs NÃO; Pergunta do modelo de dados do Cassandra

  • 772

Eu tenho um cluster de brinquedo Cassandra rodando em alguns RaspberryPis em casa. Atualmente, estou registrando dados da CryptoCoin na esperança de aprender mais sobre Cassandra e outras coisas ao longo do caminho.

Minha dúvida aqui hoje é saber se estou estruturando meu esquema corretamente nesta tabela.

A tabela não possui muitos campos, as chaves primárias são o campo de nome e o campo de carimbo de data/hora. Quero consultar as últimas N horas de dados (os dados são registrados a cada minuto) de todas as moedas. Se eu usar uma cláusula WHERE simples, recebo o aviso 'ALLOW FILTERING'. Eu entendo por que isso acontece, mas estou lutando para entender o caminho correto a seguir para garantir uma solução escalável. No momento, a tabela tem apenas cerca de 320k registros e posso usar ALLOW FILTERING sem problemas, mas percebo que isso nem sempre pode ser o caso.

Eu configurei um teste para ver quanto tempo levou para executar dois métodos de consulta diferentes. O método ALLOW FILTERING atualmente é o mais rápido, mas é provável que continue assim? É aqui que eu sou deficiente em conhecimento.

Eu tive uma ideia de adicionar outro campo que seria o dia da semana, e talvez um campo do mês também. O pensamento era que isso poderia permitir mais filtragem em uma consulta para que eu não precisasse percorrer todas as moedas como estou fazendo abaixo, mas não sei se isso é uma boa ideia ou não. Se eu fizer isso, faço deles uma chave primária ou não? Acho que é aqui que estou mais confuso com Cassandra, mas não inteiramente; talvez apenas o suficiente para ser inseguro.

Descrição da Tabela CQL:

CREATE TABLE cryptocoindb.worldcoinindex (
    name text,
    timestamp int,
    label text,
    price_btc double,
    price_cny double,
    price_eur double,
    price_gbp double,
    price_rur double,
    price_usd double,
    volume_24h double,
    PRIMARY KEY (name, timestamp)
) WITH CLUSTERING ORDER BY (timestamp ASC)
    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', 'max_threshold': '32', 'min_threshold': '4'}
    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND crc_check_chance = 1.0
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99PERCENTILE';

Código em Python:

# First method using ALLOW FILTERING:
startTime = time.time()
oneDaySec = 60*60*24
prior24hr = int(time.time()-oneDaySec)

query = "SELECT * FROM {}.{} WHERE timestamp > {} ALLOW FILTERING;".format(CASSANDRA_DB, CASSANDRA_TABLE, prior24hr)

rslt = session.execute(query, timeout=None)
worldcoinindex = rslt._current_rows
elapseTime = time.time()-startTime

print("Elapsed Time for this method: {}".format(elapseTime))

Tempo decorrido para este método: 0,6223547458648682

# Second method using multiple queries...

startTime = time.time()

# I get the unique coin names here.
qryGetCoinList = "SELECT DISTINCT name FROM {}.{};".format(CASSANDRA_DB, CASSANDRA_TABLE)
rslt = session.execute(qryGetCoinList, timeout=None)
rsltGetCoinList = rslt._current_rows
rsltGetCoinList = rsltGetCoinList.name.tolist()

oneDaySec = 60*60*24
prior24hr = int(time.time()-oneDaySec)

# This iterates over the unique coin names and queries 
# the last 24 hrs worth of data per coin.
# NOTE: There are 518 unique coins.  

rsltTodayPrices = pd.DataFrame()
for coin in rsltGetCoinList:

    qryTodayPrices = """
                    SELECT * FROM {}.{} 
                    WHERE name = '{}' AND timestamp > {};
                    """.format(CASSANDRA_DB, 
                               CASSANDRA_TABLE, 
                               coin, 
                               prior24hr)
    rslt = session.execute(qryTodayPrices, timeout=None)
    TodayPrices = rslt._current_rows
    rsltTodayPrices.append(TodayPrices)

elapseTime = time.time()-startTime
print("Elapsed Time for this method: {}".format(elapseTime))

Tempo decorrido para este método: 1,4576539993286133

Obrigada!

nosql schema
  • 1 1 respostas
  • 5963 Views

1 respostas

  • Voted
  1. Best Answer
    Aaron
    2017-08-26T09:28:47+08:002017-08-26T09:28:47+08:00

    No momento, a tabela tem apenas cerca de 320k registros e posso usar ALLOW FILTERING sem problemas, mas percebo que isso nem sempre pode ser o caso.

    Então é o seguinte: Cassandra é muito boa em consultar dados por uma chave específica. Também é bom para recuperar um intervalo de dados dentro de uma partição.

    "SELECT * FROM {}.{} WHERE timestamp > {} ALLOW FILTERING;"
    

    Mas devido à sua natureza distribuída, não é bom escanear uma tabela inteira para compilar um conjunto de resultados. E é isso que você está pedindo para fazer com a consulta acima.

    O tráfego de rede é caro. Portanto, o principal objetivo com o Cassandra é garantir que sua consulta seja atendida por um único nó. Ao usar ALLOW FILTERINGsem especificar sua chave de partição (nome) faz com que sua consulta exija um nó coordenador e verifique cada nó em seu cluster para valores que possam corresponder à sua cláusula WHERE.

    Essencialmente, quanto mais nós houver em seu cluster, mais prejudicial ALLOW FILTERINGse tornará para o desempenho (a menos que você especifique pelo menos sua chave de partição... somente então você estará garantindo que sua consulta possa ser atendida por um único nó). Observe que sua consulta mais lenta realmente faz isso corretamente e resolve esse problema para você.

    Eu tive uma ideia de adicionar outro campo que seria o dia da semana, e talvez um campo do mês também.

    E esta é uma boa ideia!

    Resolve dois problemas.

    1. Ele garante que sua consulta seja atendida por um único nó.
    2. Ele protege suas partições de ficarem muito grandes.

    Cassandra tem um limite de 2 bilhões de células por partição. Como sua chave de partição é "nome" e você continua adicionando carimbos de data e hora exclusivos dentro dela, você progredirá em direção a esse limite até alcançá-lo ou sua partição se tornar grande demais para usar (provavelmente o último).

    Aqui está como eu resolveria isso:

    CREATE TABLE cryptocoindb.worldcoinindex_byday (
        daybucket text,
        name text,
        datetime timestamp,
        label text,
        price_btc double,
        price_cny double,
        price_eur double,
        price_gbp double,
        price_rur double,
        price_usd double,
        volume_24h double,
        PRIMARY KEY (daybucket, datetime, name)
    ) WITH CLUSTERING ORDER BY (datetime DESC, name ASC);
    

    Agora você pode consultar assim:

    SELECT * FROM cryptocoindb.worldcoinindex
    WHERE daybucket='20170825' AND datetime > '2017-08-25 17:20';
    

    Além disso, ao agrupar suas linhas em "datetime" descendente, você garante que os dados mais recentes estejam no topo de cada célula (dando a Cassandra menos necessidade de analisar).

    Mudei "name" para ser a última coluna de agrupamento, apenas para manter a exclusividade. Se você nunca vai consultar por "nome", não faz sentido usá-lo como sua chave de partição.

    Espero que isto ajude.

    Observação: alterei seu timestamp intpara datetime timestampporque acrescentou clareza ao exemplo. Você pode usar o que funcionar para você, mas tome cuidado com a confusão que surge ao nomear uma coluna após um tipo de dados.

    Editar 20170826

    O seguinte é o mesmo que o seu código ou diferente?PRIMARY KEY ((daybucket, datetime), name)

    Não, isso não é o mesmo. Isso está usando algo chamado chave de partição composta. Isso lhe dará uma melhor distribuição de dados em seu cluster, mas tornará a consulta mais difícil para você e basicamente fará com que você volte a fazer varreduras de tabela.

    Para uma boa e abrangente descrição das chaves primárias do Cassandra, Carlo Bertuccini tem uma ótima resposta no StackOverflow:

    https://stackoverflow.com/questions/24949676/difference-between-partition-key-composite-key-and-clustering-key-in-cassandra/24953331#24953331

    Existe uma maneira de alterar a maneira como o Cassandra lê os carimbos de data/hora ou uma maneira fácil de fazer alterações em todo o campo de dados para alterar o carimbo de data/hora para que seja lido corretamente?

    Na verdade, não. Os carimbos de data e hora do Cassandra podem ser complicados de trabalhar. Eles armazenam com precisão de milissegundos, mas na verdade não mostram essa precisão total quando consultados. Além disso, a partir de um dos patches 2.1, ele exibe automaticamente a hora em GMT; então isso pode ser confuso para as pessoas também. Se sua maneira de gerenciar carimbos de data/hora no lado do aplicativo estiver funcionando para você, continue com isso.

    • 10

relate perguntas

  • "phpMyAdmin" para Cassandra

  • PostgreSQL: data de criação de uma tabela

  • Existe alguma ferramenta boa para fazer Design de Banco de Dados e Protótipos? [fechado]

  • Quão errado está meu esquema de modelagem de aplicativo da web?

  • Quais são as diferenças entre o NoSQL e um RDBMS tradicional?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve