Visão geral
- Usa
serdepara codificar/decodificar linhas. - Suporta atributos do
serde:skip_serializing,skip_deserializing,rename. - Usa o formato
RowBinaryno transporte HTTP.- Há planos para migrar para
Nativesobre TCP.
- Há planos para migrar para
- Suporta TLS (por meio das features
native-tlserustls-tls). - Suporta compressão e descompressão (LZ4).
- Fornece APIs para selecionar ou inserir dados, executar DDLs e fazer batching no cliente.
- Fornece mocks úteis para testes unitários.
Instalação
Cargo.toml:
Recursos do Cargo
lz4(ativado por padrão) — habilita as variantesCompression::Lz4eCompression::Lz4Hc(_). Quando ativado,Compression::Lz4é usado por padrão em todas as queries, exceto paraWATCH.native-tls— oferece suporte a URLs com o schemaHTTPSviahyper-tls, que faz link com o OpenSSL.rustls-tls— oferece suporte a URLs com o schemaHTTPSviahyper-rustls, que não faz link com o OpenSSL.inserter— habilitaclient.inserter().test-util— adiciona mocks. Veja o exemplo. Use-o apenas emdev-dependencies.watch— habilita a funcionalidadeclient.watch. Consulte a seção correspondente para mais detalhes.uuid— adicionaserde::uuidpara funcionar com a crate uuid.time— adicionaserde::timepara funcionar com a crate time.
Compatibilidade entre versões do ClickHouse
wa-37420 para resolver esse problema. Observação: esse recurso não deve ser usado com versões mais recentes do ClickHouse.
Exemplos
Uso
O crate ch2rs é útil para gerar um tipo de linha com base no ClickHouse.
Criando uma instância de cliente
Conexão HTTPS ou ClickHouse Cloud
rustls-tls ou native-tls.
Em seguida, crie o cliente normalmente. Neste exemplo, as variáveis de ambiente são usadas para armazenar os detalhes da conexão:
- Exemplo de HTTPS com ClickHouse Cloud no repositório do cliente. Isso também deve ser aplicável a conexões HTTPS em ambientes on-premise.
Selecionando linhas
- O marcador
?fieldsé substituído porno, name(campos deRow). - O marcador
?é substituído pelos valores nas chamadasbind()a seguir. - Os métodos práticos
fetch_one::<Row>()efetch_all::<Row>()podem ser usados para obter a primeira linha ou todas as linhas, respectivamente. sql::Identifierpode ser usado para associar nomes de tabelas.
query(...).with_option("wait_end_of_query", "1") para ativar a bufferização da resposta no servidor. Mais detalhes. A opção buffer_size também pode ser útil.
Inserção de linhas
- Se
end()não for chamado, oINSERTserá abortado. - As linhas são enviadas progressivamente como um stream para distribuir a carga de rede.
- O ClickHouse insere lotes de forma atômica somente se todas as linhas couberem na mesma partição e se a quantidade delas for menor que
max_insert_block_size.
Async insert (batching no servidor)
async_insert ao método insert (ou até mesmo à própria instância Client, para que isso afete todas as chamadas de insert).
- Exemplo de async insert no repositório do cliente.
Recurso Inserter (batching no cliente)
inserter do Cargo.
Inserterencerra a inserção ativa emcommit()se qualquer um dos limites (max_bytes,max_rows,period) for atingido.- O intervalo entre o encerramento de
INSERTs ativos pode ser ajustado comwith_period_biaspara evitar picos de carga causados por insertores paralelos. Inserter::time_left()pode ser usado para detectar quando o período atual termina. ChameInserter::commit()novamente para verificar os limites se o seu stream emitir itens com pouca frequência.- Os limiares de tempo são implementados com o crate quanta para acelerar o
inserter. Ele não é usado setest-utilestiver habilitado (assim, o tempo pode ser controlado portokio::time::advance()em testes personalizados). - Todas as linhas entre chamadas de
commit()são inseridas na mesma instruçãoINSERT.
Executando DDLs
wait_end_of_query. Isso pode ser feito assim:
Configurações do ClickHouse
with_option. Por exemplo:
query, isso funciona de maneira semelhante nos métodos insert e inserter; além disso, o mesmo método pode ser chamado na instância Client para definir configurações globais para todas as consultas.
ID da consulta
.with_option, você pode definir a opção query_id para identificar consultas no log de consultas do ClickHouse.
query, ele também funciona de forma semelhante com os métodos insert e inserter.
Se você definir
query_id manualmente, certifique-se de que ele seja único. UUIDs são uma boa escolha para isso.ID da sessão
query_id, você pode definir session_id para executar as instruções na mesma sessão. session_id pode ser definido globalmente no nível do cliente ou por chamada de query, insert ou inserter.
Em implantações em cluster, devido à ausência de “sticky sessions”, você precisa estar conectado a um nó específico do cluster para usar esse recurso corretamente, pois, por exemplo, um balanceador de carga round-robin não garante que as solicitações subsequentes sejam processadas pelo mesmo nó do ClickHouse.
Cabeçalhos HTTP personalizados
Cliente HTTP personalizado
Tipos de dados
Veja também estes exemplos adicionais:
(U)Int(8|16|32|64|128)corresponde aos tipos(u|i)(8|16|32|64|128)equivalentes, ou a newtypes baseados neles.(U)Int256não tem suporte direto, mas há uma solução alternativa.Float(32|64)corresponde aos tiposf(32|64)equivalentes, ou a newtypes baseados neles.Decimal(32|64|128)corresponde aos tiposi(32|64|128)equivalentes, ou a newtypes baseados neles. É mais prático usarfixnumou outra implementação de números com sinal em ponto fixo.Booleancorresponde aboolou a newtypes baseados nele.Stringcorresponde a qualquer tipo de string ou bytes, por exemplo,&str,&[u8],String,Vec<u8>ouSmartString. Newtypes também têm suporte. Para armazenar bytes, considere usarserde_bytes, pois é mais eficiente.
FixedString(N)tem suporte como um array de bytes, por exemplo[u8; N].
Enum(8|16)têm suporte por meio deserde_repr.
UUIDé mapeado de e parauuid::Uuidusandoserde::uuid. Requer o recursouuid.
IPv6é convertido de/parastd::net::Ipv6Addr.IPv4é convertido de/parastd::net::Ipv4Addrusandoserde::ipv4.
Dateé mapeado de/parau16ou um newtype baseado nele e representa um número de dias decorridos desde1970-01-01. Além disso,time::Datetambém é compatível com o uso deserde::time::date, o que requer o recursotime.
Date32é mapeado de/parai32ou umnewtypebaseado nele e representa um número de dias decorridos desde1970-01-01. Além disso,time::Datetambém é compatível com o uso deserde::time::date32, o que requer o recursotime.
DateTimeé convertido de/parau32ou um newtype baseado nele e representa um número de segundos decorridos desde a epoch UNIX. Além disso,time::OffsetDateTimeé compatível ao usarserde::time::datetime, o que requer o recursotime.
DateTime64(_)é mapeado de/parai32ou um newtype baseado nele e representa o tempo decorrido desde a epoch UNIX. Além disso,time::OffsetDateTimetambém tem suporte usandoserde::time::datetime64::*, o que exige a featuretime.
Tuple(A, B, ...)é mapeado de/para(A, B, ...)ou umnewtypesobre ele.Array(_)é mapeado de/para qualquer slice, por exemploVec<_>,&[_].newtypestambém são compatíveis.Map(K, V)se comporta comoArray((K, V)).LowCardinality(_)tem suporte transparente.Nullable(_)é mapeado de/paraOption<_>. Para os helpersclickhouse::serde::*, adicione::option.
- Há suporte a
Nestedao fornecer vários arrays com renomeação.
- Há suporte a tipos
Geo.Pointse comporta como uma tupla(f64, f64), e os demais tipos são apenas sequências de pontos.
- Os tipos de dados
Variant,Dynamice o (novo)JSONainda não têm suporte.
Simulação
SELECT, INSERT e WATCH. Esse recurso pode ser habilitado com o recurso test-util. Use-a apenas como dev-dependency.
Veja o exemplo.
Solução de problemas
CANNOT_READ_ALL_DATA
CANNOT_READ_ALL_DATA é que a definição da linha no lado da aplicação não corresponde à do ClickHouse.
Considere a seguinte tabela:
EventLog estiver definido no lado da aplicação com tipos incompatíveis, por exemplo:
EventLog:
Limitações conhecidas
- Os tipos de dados
Variant,DynamiceJSON(novo) ainda não são suportados. - O binding de parâmetros no servidor ainda não é suportado; consulte esta issue para acompanhar.