Snowflake MigrationClickHouse Workshops

05 Benchmark e virada

Reconstrua os dashboards no ClickHouse, compare as sete consultas nos dois mecanismos, faça a virada do produtor, verifique a paridade e desmonte os ambientes.

Ponto de partida

Módulo 04 concluído: a camada de analytics está preenchida e testada. analytics.fact_trips contém cerca de 50 milhões de linhas; analytics.dim_taxi_zones, analytics.dim_payment_type, analytics.dim_vendor e analytics.dim_date estão totalmente carregadas; dbt test passa de ponta a ponta; e analytics.taxi_zones_dict está ativo e retorna boroughs por meio de dictGet(). analytics.agg_hourly_zone_trips continua vazia — por decisão de projeto, não por defeito — e permanece assim até a virada deste módulo. O produtor do Snowflake continua em execução, e a lacuna entre o Snowflake e o ClickHouse permanece aberta. Reserve cerca de 45 minutos.

Por quê

Todos os módulos até aqui foram uma preparação. O módulo 03 provou que o ClickHouse consegue armazenar 50 milhões de linhas; o módulo 04 provou que o pipeline dbt funciona nele. Isoladamente, nenhum dos dois bastaria para um parceiro aprovar a migração: ainda são necessários um número e uma virada.

O número vem do benchmark da Etapa 2: as mesmas sete consultas do seu plano de migração, executadas em sequência no Snowflake e no ClickHouse, com a mediana de três execuções em cada um. É isso que transforma “o ClickHouse deve ser mais rápido” em um ganho de velocidade específico e defensável, que o parceiro pode apresentar às próprias partes interessadas.

A virada da Etapa 3 é a outra metade. Até agora, todos os módulos mantiveram os dois sistemas em execução lado a lado, com o Snowflake como sistema de registro e o ClickHouse recuperando o atraso. Uma migração que nunca transfere de fato o caminho de gravação é uma cópia, não uma migração. A Etapa 3 interrompe o produtor do Snowflake, fecha a lacuna que suas gravações contínuas mantêm aberta desde o módulo 01 e passa a gravar as novas corridas no ClickHouse — o momento em que o ClickHouse se torna o sistema de registro.

Este também é o último módulo do participante antes da avaliação escrita do módulo 06, que permite a consulta de tudo o que você produzir aqui. Os dashboards, o CSV do benchmark e a verificação de paridade precisam ser reais antes de você desmontar os ambientes na Etapa 5.

Conceitos — por baixo dos panos

A camada de BI, na prática. Na Etapa 1, bash superset/add_clickhouse_connection.sh chama diretamente a API REST do Superset — não é necessário percorrer manualmente a interface. O script registra a conexão com o ClickHouse e importa a exportação de dashboard incluída no repositório, adicionando quatro dashboards do ClickHouse aos três dashboards do Snowflake criados no módulo 01 (sete no total):

DashboardEspelhaO que demonstra
CH — Operations Command CenterSnowflake Dashboard 1Dados ativos de fact_trips (após a virada); mesmos KPIs, consultas mais rápidas
CH — Executive Weekly ReportSnowflake Dashboard 2QUALIFY reescrito como uma subconsulta com ROW_NUMBER()
CH — Driver & Quality AnalyticsSnowflake Dashboard 3JSONExtractString no lugar de LATERAL FLATTEN do Snowflake
CH — Capabilities Showcase(novo — sem equivalente no Snowflake)Funções aproximadas, junções com dicionário e a cláusula SAMPLE

O que as sete consultas de benchmark exercitam. A Etapa 2 executa as mesmas sete consultas do seu plano de migração nos dois mecanismos e compara o tempo decorrido. Cada uma aborda uma diferença específica de dialeto ou um recurso do mecanismo registrado no plano do módulo 02:

ConsultaO que exercita
Q1Receita por hora e borough
Q2Média móvel da distância em 7 dias
Q310 principais corridas — QUALIFY do Snowflake versus uma subconsulta com ROW_NUMBER() no ClickHouse
Q4Avaliações de motoristas — LATERAL FLATTEN do Snowflake versus JSONExtractString do ClickHouse
Q5Preço dinâmico — VARIANT do Snowflake versus String + JSONExtract* do ClickHouse
Q6Agregação por hora — MERGE do Snowflake versus ReplacingMergeTree do ClickHouse
Q7CDC / atualização dos dados ativos

A lacuna da virada. O produtor do Snowflake grava cerca de 60 corridas por minuto desde o módulo 01 e nunca foi interrompido. O script de migração do módulo 03 capturou TRIPS_RAW no estado em que ela se encontrava quando o script foi executado, e o módulo 04 criou o pipeline dbt sobre esse snapshot. Todas as corridas gravadas no Snowflake desde o último lote do script de migração existem apenas no Snowflake — o trecho final está ausente no ClickHouse. A passagem de recuperação com --resume da Etapa 3 fecha exatamente essa lacuna: ela lê o max(pickup_at) já presente no ClickHouse e recupera apenas as linhas gravadas depois desse ponto. Assim, uma passagem que fecha uma lacuna aberta desde o módulo 01 leva de segundos a minutos, não os 40 a 50 minutos da migração em massa original. Se você ignorá-la e fizer a virada mesmo assim, o ClickHouse perderá permanentemente todas as corridas inseridas durante a lacuna — uma falha silenciosa de paridade que a Etapa 4 foi feita para detectar, mas somente se a Etapa 3 for executada na ordem correta.

agg_hourly_zone_trips é preenchida aqui, e somente aqui. Ela está vazia desde o módulo 03 por decisão de projeto: seu filtro incremental é WHERE pickup_at >= now() - INTERVAL 2 HOUR, que corresponde apenas às linhas gravadas por um produtor ativo, e até este módulo o Snowflake era o único destino das gravações do produtor. Quando a Etapa 3 inicia o produtor do ClickHouse, as novas linhas finalmente entram nessa janela de duas horas, e a tabela — junto com todos os gráficos de dashboard baseados nela — deixa de ficar em branco pela primeira vez no laboratório.

Etapa 1 — Adicionar os dashboards do ClickHouse

Para realizar a criação manual completa — criando passo a passo cada um dos 7 conjuntos de dados, 18 gráficos e 4 dashboards na interface do Superset —, siga Superset no ClickHouse. Para pular as etapas manuais e importar tudo de uma só vez:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && source .clickhouse_state
bash superset/add_clickhouse_connection.sh

O host do ClickHouse no arquivo superset/dashboards/dashboard_export_*.zip incluído no repositório foi substituído por your-instance.clickhouse.cloud. O atalho acima corrige a URI a partir de .env antes da importação, portanto isso é transparente — você nem perceberá a substituição. Porém, se você importar o ZIP manualmente pela interface do Superset, a conexão de banco de dados criada por ele não funcionará — será necessário editá-la depois para que aponte para o CLICKHOUSE_HOST e as credenciais corretos. Consulte Superset no ClickHouse para ver o procedimento exato.

Verificação:

Abra http://localhost:8088 (admin / admin). Em Dashboards, devem aparecer 7 itens no total — 3 dashboards do Snowflake e 4 com o prefixo CH —.

Etapa 2 — Executar o benchmark

Execute as sete consultas em sequência no Snowflake e no ClickHouse e compare o tempo decorrido:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && source .clickhouse_state
./scripts/run_benchmark.sh

Saída esperada:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  NYC Taxi Lab — Query Benchmark: Snowflake vs ClickHouse
  (median of 3 runs each)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Query                                   Snowflake     ClickHouse    Speedup
────────────────────────────────────────────────────────────────────────
Q1  Hourly revenue by borough           5.0s          0.7s          6x
Q2  Rolling 7-day avg distance          5.5s          0.8s          6x
Q3  Top 10 trips (QUALIFY→subquery)     5.0s          0.7s          6x
Q4  Driver ratings (JSON flatten)       5.4s          0.8s          6x
Q5  Surge pricing (VARIANT)             5.1s          0.7s          6x
Q6  Hourly aggregation (MERGE→RMT)      5.9s          0.8s          7x
Q7  CDC/live data freshness             7.9s          0.8s          9x
────────────────────────────────────────────────────────────────────────
Total                                   40.1s         5.6s          7x avg
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Esses números são de uma execução representativa, não uma garantia — seus resultados variarão conforme o tamanho do warehouse, o nível do ClickHouse Cloud e quaisquer outras cargas em execução nos dois serviços naquele momento.

O script grava cada execução em workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/scripts/benchmark_results_<timestamp>.csv. Mantenha o arquivo no disco — ele é um dos dois arquivos necessários para a avaliação do módulo 06; portanto, não o exclua durante a desmontagem da Etapa 5.

Etapa 3 — Fazer a virada para o ClickHouse

Lacuna da migração. O produtor do Snowflake permaneceu em execução durante todo o laboratório, gravando cerca de 60 corridas por minuto. O script de migração do módulo 03 capturou TRIPS_RAW como ela se encontrava quando esse script foi executado — as linhas gravadas depois disso existem apenas no Snowflake. Feche essa lacuna antes de transferir o caminho de gravação.

Execute as quatro etapas abaixo, na ordem indicada — é essa ordem que mantém a consistência entre os dois sistemas:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && source .clickhouse_state
source .venv/bin/activate

# Step 1: Stop the Snowflake producer (freeze the dataset)
docker stop nyc_taxi_producer

# Step 2: Catch up the delta — only migrates rows with pickup_at newer than
# what's already in ClickHouse. Runs in seconds to minutes, not the original
# 40-50 minutes, because only the gap rows move.
python scripts/02_migrate_trips.py --resume

# Step 3: Refresh the analytics tables with the newly migrated rows
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/dbt/nyc_taxi_dbt_ch"
dbt run
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"

# Step 4: Start the ClickHouse producer
source .env && source .clickhouse_state
./scripts/03_cutover.sh

Não pule a Etapa 2. --resume lê o max(pickup_at) já presente no ClickHouse e adiciona um filtro WHERE PICKUP_DATETIME > <watermark> à consulta do Snowflake. Assim, ele transfere somente as linhas gravadas durante e depois da execução da migração original no módulo 03 — aquelas que o ClickHouse nunca viu. Fazer a virada sem isso levaria o ClickHouse a perder permanentemente todas as corridas inseridas nessa janela. A verificação de paridade da Etapa 4 foi feita para detectar exatamente esse problema, mas somente se esta etapa for executada primeiro.

./scripts/03_cutover.sh exibe a solicitação Type "cutover" to confirm e, em seguida, repete as etapas de 1 a 3 como uma proteção adicional: interrompe novamente o produtor do Snowflake (sem efeito se isso já foi feito), executa mais um dbt run e depois cria e inicia o produtor do ClickHouse (nyc_taxi_ch_producer). Trinta segundos após o início do produtor, o script confirma que novas linhas estão chegando a default.trips_raw e executa o dbt mais uma vez — é essa execução que finalmente fornece as primeiras linhas a agg_hourly_zone_trips, fechando a lacuna que o módulo 04 deixou aberta intencionalmente.

Verificação:

-- Most recent trip should be within the last 60 seconds
SELECT max(pickup_at) AS most_recent_trip FROM default.trips_raw;

-- Row count should be increasing — wait 60 seconds and run again
SELECT count() FROM default.trips_raw;

-- agg_hourly_zone_trips should now have rows for the first time in the lab
SELECT count() FROM analytics.agg_hourly_zone_trips;
docker ps | grep nyc_taxi_ch_producer   # should show running

Como manter a camada de analytics atualizada. fact_trips e agg_hourly_zone_trips são modelos incrementais do dbt — eles não se atualizam automaticamente. 03_cutover.sh executa dbt run uma vez depois de confirmar que o produtor está ativo, mas os dashboards ficam defasados à medida que novas corridas se acumulam; execute novamente dbt run em dbt/nyc_taxi_dbt_ch sempre que quiser números atuais (em produção, você agendaria essa execução — com cron, Airflow ou dbt Cloud —, mas sob demanda é suficiente no laboratório). Por outro lado, analytics.mv_live_trip_feed é uma view materializada atualizável — o dbt run do módulo 04 já a criou com engine = 'ReplacingMergeTree(refreshed_at)' —, mas o laboratório nunca ativa seu intervalo de atualização: a instrução MODIFY REFRESH EVERY 30 SECOND, que faria a view executar novamente por conta própria, existe apenas como comentário no arquivo do modelo. Para ativá-la, você executaria por conta própria uma única instrução ALTER TABLE; sem isso, mv_live_trip_feed é atualizada somente uma vez, quando o dbt a cria.

Virada reversa, caso seja necessário desfazer esta etapa e voltar ao produtor do Snowflake:

docker stop nyc_taxi_ch_producer
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake/superset"
docker-compose --env-file ../.env up -d producer

Etapa 4 — Verificar a paridade

Agora que a passagem de recuperação com --resume foi executada e o produtor do ClickHouse está ativo, os dois sistemas devem estar em paridade. Confirme:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && source .clickhouse_state
bash scripts/01_verify_migration.sh

Saída esperada:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  Migration Parity Check
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✓ ClickHouse default.trips_raw: 50,008,250 rows

  ✓ Snowflake NYC_TAXI_DB.RAW.TRIPS_RAW: 50,008,250 rows
  ✓ Row count parity: PASS  (difference: 0 rows = 0.0000%)

  ✓ trip_metadata populated: 50,008,250 non-empty rows
  pickup_at range: 2022-03-30   2026-03-31

  ✓ ClickHouse has 50,008,250 rows — migration looks complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Sua contagem de linhas será diferente; o que importa é a linha de paridade. Nesse ponto, o produtor do Snowflake já foi interrompido, portanto nenhuma linha nova está sendo inserida ali — as contagens devem coincidir exatamente ou diferir por poucas linhas, caso um lote ainda estivesse em andamento durante a passagem com --resume, bem abaixo do limite de 0,01% verificado pelo script.

Se a verificação de paridade falhar (diferença superior a 0,01%), a lacuna não foi totalmente fechada — execute novamente a passagem de recuperação e repita a verificação:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && source .clickhouse_state
python scripts/02_migrate_trips.py --resume
bash scripts/01_verify_migration.sh

Etapa 5 — Desmontar os ambientes

Antes de desmontar qualquer coisa, confirme que a migração está em um estado final correto:

VerificaçãoComandoResultado esperado
Paridade da contagem de linhasbash scripts/01_verify_migration.shCorrespondência da contagem de linhas ≥ 99,9%
Testes do dbtdbt test (em dbt/nyc_taxi_dbt_ch)Todos os testes passam
Dashboards do SupersetAbra http://localhost:80887 dashboards visíveis (3 SF + 4 CH)
Resultados do benchmarkcat scripts/benchmark_results_<timestamp>.csvAs 7 consultas têm um valor de ganho de velocidade
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && source .clickhouse_state
bash scripts/01_verify_migration.sh

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/dbt/nyc_taxi_dbt_ch"
dbt test

Quando as quatro verificações passarem, dois arquivos são tudo o que o módulo 06 exige, e ambos sobrevivem à desmontagem: workshop_public/snowflake_migration_lab/02-plan-and-design/migration-plan.md e workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/scripts/benchmark_results_<timestamp>.csv. O módulo 06 é uma avaliação escrita com consulta, leva cerca de 60 minutos e não precisa de mais nada — não há motivo para manter um serviço pago do ClickHouse Cloud em execução durante uma prova escrita. Copie ou anote o conteúdo dos dois arquivos em um local acessível e, em seguida, desmonte tudo:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse"
source .env && ./teardown.sh

Esse comando destrói o serviço do ClickHouse Cloud (por meio de terraform destroy) e o contêiner do produtor de corridas do ClickHouse, caso a virada tenha sido realizada.

Os recursos do Snowflake da Parte 1 não são desmontados por esse script. Desmonte a parte do Snowflake separadamente:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake"
source .env && ./teardown.sh

Como verificar se você terminou

Neste ponto do módulo, você deve ter confirmado, na seguinte ordem:

  • A verificação de paridade passou — o 01_verify_migration.sh da Etapa 4 relatou PASS com uma diferença na contagem de linhas inferior a 0,01%.
  • O CSV do benchmark está no disco — a Etapa 2 gravou benchmark_results_<timestamp>.csv com um valor de ganho de velocidade para cada uma das 7 consultas, e você o guardou antes da desmontagem na Etapa 5.
  • Os 7 dashboards estão presentes — a verificação do Superset da Etapa 1 mostrou lado a lado 3 dashboards do Snowflake e 4 dashboards CH —.
  • O produtor do ClickHouse estava gravando — o bloco de verificação da Etapa 3 mostrou default.trips_raw recebendo novas linhas e nyc_taxi_ch_producer em execução, antes que a Etapa 5 o interrompesse para a desmontagem.

Se alguma dessas condições não era verdadeira naquele momento, volte à etapa correspondente, em vez de tentar executar novamente as verificações agora — a Etapa 5 já destruiu o serviço do ClickHouse Cloud e, caso a virada tenha ocorrido, também o contêiner do produtor.

Estado final

A migração está concluída e medida: 50 milhões de linhas foram transferidas do Snowflake para o ClickHouse e tiveram a paridade verificada; sete consultas foram comparadas diretamente, com o ClickHouse mais rápido em todas elas; a camada de BI foi reconstruída com 4 dashboards do ClickHouse ao lado dos 3 dashboards originais do Snowflake; e o caminho de gravação foi transferido definitivamente do Snowflake para o ClickHouse. Os dois ambientes de nuvem foram desmontados — sem serviço do ClickHouse Cloud, sem contêiner do produtor do ClickHouse e, depois que a desmontagem da Parte 1 também for executada, sem warehouse do Snowflake.

Dois arquivos sobrevivem à desmontagem e são tudo o que o módulo 06 exige: workshop_public/snowflake_migration_lab/02-plan-and-design/migration-plan.md e workshop_public/snowflake_migration_lab/03-migrate-to-clickhouse/scripts/benchmark_results_<timestamp>.csv. O módulo 06 é uma avaliação escrita com consulta — leve apenas esses dois arquivos.

Nesta página

Acompanhar seu progresso?

Opcional. Enviaremos um link por e-mail para confirmar seu endereço; o progresso será registrado depois que você o abrir.

Use seu e-mail corporativo, não um endereço pessoal.

O acompanhamento do progresso também exige a aceitação dos Termos de Serviço atuais nas Configurações de privacidade.

PT