Posicionamento
Os processos ETL são a espinha dorsal de qualquer plataforma de dados. Eles determinam se relatórios, indicadores e dashboards estão disponíveis de forma confiável, completa e pontual. Um data warehouse é sempre tão bom quanto os processos de carga que o alimentam. É exatamente aqui que está o meu foco: desenvolvo pipelines ETL e ELT que não apenas funcionam na primeira execução, mas que permanecem estáveis, compreensíveis e manuteníveis em operação contínua.
Trabalho com bancos de dados desde 1994 e com tecnologias de data warehouse e ETL desde o início dos anos 2000. Nesse período, implementei processos ETL com ferramentas muito diversas: Microsoft SSIS e T-SQL, Informatica PowerCenter, Oracle Data Integrator, scripts BTEQ do Teradata, scripts Shell, Perl e PowerShell, e cada vez mais com Azure Data Factory, Azure Synapse e Databricks. Essa amplitude me permite analisar os processos de carga não pela ótica de uma única ferramenta, mas pela ótica da tarefa real: transportar dados de forma confiável de A para B, aplicando as transformações corretas do ponto de vista de negócio.
Essa longa experiência, atravessando inúmeras mudanças tecnológicas, molda minha forma de trabalhar. Acompanhei a evolução dos pipelines ETL desde arquiteturas puramente baseadas em mainframe, passando por ferramentas cliente-servidor, até chegar a pipelines nativos de nuvem. O que nunca mudou foram as perguntas fundamentais do negócio: Os dados estão completos? Estão corretos? Chegaram no prazo? É possível rastrear a origem de um valor? É exatamente com essas perguntas em mente que estruturo cada pipeline ETL, independentemente de ser implementado com SSIS, T-SQL ou Databricks. As ferramentas são meios para um fim — a confiabilidade é o objetivo.
Os clientes geralmente me contratam quando precisam de pipelines de dados robustos que sustentem o negócio no dia a dia: relatórios para a controladoria, análises regulatórias em ambientes bancários e de órgãos públicos, indicadores para a gestão ou entregas de dados para sistemas downstream. Em todos esses contextos, uma falha no pipeline ETL não é um problema técnico marginal — tem consequências imediatas para o negócio. Levo essa responsabilidade a sério e projeto os pipelines desde o início pensando em estabilidade, rastreabilidade e manutenibilidade.
O que significa desenvolver ETL na prática
ETL significa Extract, Transform, Load. Na prática, porém, isso é apenas o enquadramento geral de uma série de tarefas detalhadas que determinam o sucesso ou o fracasso de um projeto de dados. Quem entende os processos ETL apenas como 'copiar dados da fonte para a tabela de destino' cedo ou tarde será surpreendido pela realidade: por sistemas de origem que mudam, por problemas de qualidade de dados, por picos de carga, por fontes que ficam indisponíveis no meio de uma execução, e por requisitos de negócio que evoluem com o tempo.
Extract — a leitura das fontes
A etapa de extração lê os dados dos sistemas de origem. Parece simples, mas é a etapa que exige mais sensibilidade. Os sistemas de origem raramente foram projetados para fornecer grandes volumes de dados para um data warehouse. São sistemas operacionais — ERP, CRM, lojas virtuais, sistemas de processos — que não podem ser sobrecarregados por consultas volumosas durante a operação. Por isso, trabalho na extração com janelas de leitura bem definidas, técnicas incrementais, Change Data Capture e, quando necessário, interfaces baseadas em arquivos via sFTP.
Nos meus projetos, integrei fontes de naturezas muito diversas: bancos de dados relacionais como SQL Server, Oracle, Informix e Teradata; fontes NoSQL como MongoDB; arquivos flat em formato de comprimento fixo e CSV; arquivos XML; APIs REST e OData; e arquivos de dados de mainframe com estrutura descrita por copybooks COBOL e PL/1. Especialmente a integração de sistemas legados demonstra que a extração vai muito além de um SELECT: trata-se de compreender a estrutura da fonte, os tipos de dados, os casos especiais e o significado de negócio de cada campo.
Transform — a lógica de negócio
A transformação é o núcleo do processo. Aqui os dados são limpos, padronizados, consolidados, enriquecidos, historicizados e adaptados às estruturas de destino. Tarefas típicas incluem a padronização de chaves, a resolução de tabelas de código, a deduplicação, o tratamento de valores NULL, o mapeamento de atributos de negócio, o cálculo de métricas derivadas e a implementação de regras de negócio. O fundamental é que cada transformação permaneça rastreável: qual regra foi aplicada, de onde vem um valor, por que um registro tem a aparência que tem?
Load — a escrita controlada
A etapa de carga grava os dados transformados nas estruturas de destino. Aqui também os detalhes fazem toda a diferença: a carga é completa ou incremental? Históricos são mantidos? O que acontece com registros excluídos na fonte? Como garantir que uma execução interrompida não deixe dados duplicados ou incompletos? Essas perguntas não são respondidas apenas no momento da falha, mas já no projeto do pipeline.
- Carga incremental em vez de Full Loads custosos, sempre que a fonte permite
- Processos de carga idempotentes, que entregam o mesmo resultado em repetições
- Separação clara entre staging, core e camada de entrega
- Logging completo com batch IDs e metadados de execução
- Testes funcionais e técnicos como parte integrante do desenvolvimento
Arquitetura de referência de um pipeline ETL
Ao longo de muitos projetos, consolidou-se uma arquitetura que processa os dados em camadas claramente separadas. Cada camada tem uma responsabilidade definida e um escopo de responsabilidade preciso. Isso torna o pipeline compreensível, testável e extensível.
Arquitetura de referência de um pipeline ETL: origens, extração, staging, transformação, Core/DWH e entrega para BI — complementados por orquestração, logging e reprocessamento.
As fontes são carregadas inicialmente, o mais intacto possível, em uma camada de staging. Essa camada de dados brutos serve como ponto de auditoria e de reprocessamento: ela registra o que foi efetivamente entregue e permite repetir uma execução sem sobrecarregar as fontes novamente. Somente na camada de transformação as regras de negócio são aplicadas. O resultado chega ao Core ou ao data warehouse, que é historicizado e otimizado para consultas analíticas. A partir do Core, são alimentadas as camadas de entrega para relatórios, cubos e modelos de BI.
A camada de staging cumpre simultaneamente várias funções. Ela desacopla a leitura das fontes do processamento dos dados, de modo que janelas de leitura curtas nos sistemas de origem sejam suficientes e a transformação — muitas vezes complexa — possa ser executada independentemente. Serve como evidência do que foi efetivamente entregue — aspecto especialmente relevante em ambientes regulados. E viabiliza o reprocessamento: se uma execução for interrompida na etapa de transformação, ela pode ser repetida a partir do staging sem onerar as fontes uma segunda vez. Em projetos com sistemas operacionais sensíveis, esse desacoplamento é frequentemente o fator determinante para uma operação sem problemas.
Entre o Core e a camada de entrega, mantenho conscientemente uma fronteira. O Core é otimizado para correção de negócio e historicização, seguindo uma modelagem estável pensada no longo prazo. A camada de entrega, por sua vez, é estruturada para as análises concretas — por exemplo, como esquema estrela para um modelo Power BI ou como visão desnormalizada para um relatório específico. Essa separação permite adicionar novas análises sem modificar o núcleo do data warehouse e, ao mesmo tempo, protege os relatórios existentes de alterações na modelagem interna.
Padrões de carga: Full Load, Delta e SCD2
A escolha do padrão de carga correto tem impacto decisivo na performance, estabilidade e valor informacional dos dados. Nos meus projetos, utilizo principalmente três padrões, frequentemente combinados conforme a tabela e as capacidades da fonte.
Três padrões de carga em comparação: Full Load, Delta/Incremental e Slowly Changing Dimension Tipo 2.
Full Load
No Full Load, a tabela de destino é completamente reconstruída — tipicamente com Truncate seguido de Insert. É simples e robusto, mas adequado apenas para volumes de dados reduzidos ou pequenas tabelas de dimensão. Em tabelas de fatos volumosas, o Full Load rapidamente se torna um gargalo.
Carga Delta e incremental
Na carga incremental, apenas os registros alterados desde a última execução são processados. Para isso é necessário um critério confiável: um timestamp, um ID sequencial, um mecanismo de Change Data Capture ou uma comparação por valores de hash. O exemplo a seguir mostra uma carga incremental típica baseada em watermark em T-SQL.
-- Carga incremental de uma tabela de staging com base em um watermark.
-- Somente registros mais recentes que a ultima execucao bem-sucedida sao lidos.
DECLARE @LastWatermark datetime2(3);
DECLARE @NewWatermark datetime2(3);
-- 1) Recuperar o ultimo watermark da tabela de controle
SELECT @LastWatermark = LastLoadedAt
FROM etl.LoadControl
WHERE TableName = N'SalesOrder';
-- 2) Determinar o valor maximo atual na origem
SELECT @NewWatermark = MAX(ModifiedDate)
FROM src.SalesOrder;
-- 3) Carregar somente o delta no staging
INSERT INTO stg.SalesOrder (OrderId, CustomerId, Amount, ModifiedDate, BatchId)
SELECT s.OrderId, s.CustomerId, s.Amount, s.ModifiedDate, @@SPID AS BatchId
FROM src.SalesOrder AS s
WHERE s.ModifiedDate > @LastWatermark
AND s.ModifiedDate <= @NewWatermark;
-- 4) Atualizar a tabela de controle somente apos sucesso
UPDATE etl.LoadControl
SET LastLoadedAt = @NewWatermark,
LastRunAt = SYSUTCDATETIME()
WHERE TableName = N'SalesOrder';O watermark é intencionalmente atualizado apenas após o carregamento bem-sucedido. Se a execução for interrompida antes disso, o mesmo delta será reprocessado na próxima vez — tornando o processo idempotente e apto ao reprocessamento.
Slowly Changing Dimensions Tipo 2
Quando não apenas o estado atual, mas também o histórico de um registro é relevante, aplica-se o padrão SCD Tipo 2. Em vez de sobrescrever o registro existente, a versão antiga é encerrada com uma data de validade e uma nova versão é inserida com a data de início de vigência. Dessa forma, qualquer análise pode ser referenciada ao estado válido na época. Implementei o SCD2 tanto de forma clássica no SSIS quanto em procedimentos T-SQL puros via statement MERGE.
-- Historicizacao de uma dimensao conforme SCD Tipo 2.
-- Registros alterados sao encerrados e inseridos como nova versao.
MERGE dim.Customer AS tgt
USING stg.Customer AS src
ON tgt.CustomerBk = src.CustomerBk
AND tgt.IsCurrent = 1
WHEN MATCHED
AND (tgt.City <> src.City OR tgt.Segment <> src.Segment)
THEN UPDATE SET
tgt.ValidTo = SYSUTCDATETIME(),
tgt.IsCurrent = 0
WHEN NOT MATCHED BY TARGET
THEN INSERT (CustomerBk, City, Segment, ValidFrom, ValidTo, IsCurrent)
VALUES (src.CustomerBk, src.City, src.Segment, SYSUTCDATETIME(), NULL, 1)
OUTPUT $action, inserted.CustomerBk INTO etl.MergeLog;
-- Para registros alterados, a nova versao atual e inserida em um segundo passo
-- (procedimento classico de dois passos do SCD2).
INSERT INTO dim.Customer (CustomerBk, City, Segment, ValidFrom, ValidTo, IsCurrent)
SELECT s.CustomerBk, s.City, s.Segment, SYSUTCDATETIME(), NULL, 1
FROM stg.Customer AS s
JOIN dim.Customer AS d
ON d.CustomerBk = s.CustomerBk AND d.IsCurrent = 0
AND d.ValidTo >= DATEADD(SECOND, -2, SYSUTCDATETIME());O MERGE é elegante, mas precisa ser testado cuidadosamente. Para tabelas muito grandes, opto frequentemente por etapas separadas de INSERT/UPDATE baseadas em conjuntos, por razões de performance e controle de bloqueios.
Desenvolvimento com SSIS e T-SQL
O Microsoft SQL Server Integration Services (SSIS) é há muitos anos minha principal ferramenta para ETL no ecossistema Microsoft. Desenvolvi, migrei, otimizei e estabilizei pacotes SSIS em inúmeros projetos — da Stadtsparkasse München à Loyalty Partner (Payback) e à Agência Federal de Emprego da Alemanha. O escopo vai de simples pipelines de importação de arquivos de texto até pacotes complexos e parametrizados com loops, contêineres, event handlers e configuração dinâmica.
Um princípio importante: o SSIS é poderoso para orquestrar, para o fluxo de dados e para conectar fontes heterogêneas. A transformação orientada a conjuntos, porém, frequentemente pertence ao banco de dados. Por isso, combino intencionalmente o SSIS com T-SQL e Stored Procedures. O pacote controla o fluxo, cuida dos arquivos, do logging e do tratamento de erros; as transformações pesadas são executadas como operações SQL baseadas em conjuntos diretamente no SQL Server, onde são mais rápidas.
O SSIS oferece ainda uma série de componentes especialmente valiosos para pipelines robustos: Foreach Loop Containers para processar diretórios inteiros de arquivos, Sequence Containers para agrupamento lógico, Event Handlers para tratamento centralizado de erros, além de variáveis e parâmetros para uma configuração limpa e dependente do ambiente. Utilizo esses recursos de forma direcionada para manter os pacotes genéricos e reutilizáveis. Um pacote master bem projetado pode processar dezenas de arquivos de origem de forma uniforme, sem que seja necessário manter um pacote separado para cada arquivo — o que reduz substancialmente o esforço de manutenção.
Stored Procedure estruturada como componente de carga
Para que a lógica ETL permaneça manutenível, encapsulo as etapas de carga em procedimentos bem estruturados com construção uniforme: validação de parâmetros, transação, tratamento de erros via TRY/CATCH e logging completo em uma tabela de protocolo centralizada. O padrão a seguir utilizo em muitas variações.
CREATE OR ALTER PROCEDURE etl.LoadSalesFact
@BatchId bigint
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON; -- reverter automaticamente em caso de erro
DECLARE @Rows int = 0;
BEGIN TRY
EXEC etl.WriteLog @BatchId, N'LoadSalesFact', N'START';
BEGIN TRANSACTION;
-- Transformacao baseada em conjuntos diretamente no SQL Server
INSERT INTO core.FactSales (DateKey, CustomerKey, ProductKey, Amount, BatchId)
SELECT d.DateKey, c.CustomerKey, p.ProductKey, s.Amount, @BatchId
FROM stg.SalesOrder AS s
JOIN core.DimDate AS d ON d.FullDate = CAST(s.ModifiedDate AS date)
JOIN core.DimCustomer AS c ON c.CustomerBk = s.CustomerId AND c.IsCurrent = 1
JOIN core.DimProduct AS p ON p.ProductBk = s.ProductId;
SET @Rows = @@ROWCOUNT;
COMMIT TRANSACTION;
EXEC etl.WriteLog @BatchId, N'LoadSalesFact', N'SUCCESS', @Rows;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
EXEC etl.WriteLog @BatchId, N'LoadSalesFact', N'ERROR', NULL, ERROR_MESSAGE();
THROW; -- propagar o erro ao job SSIS ou SQL Agent pai
END CATCH
END;O THROW ao final é fundamental: o erro é registrado, mas não suprimido. Assim, o job SSIS ou SQL Agent pai é interrompido de forma controlada e o monitoramento dispara o alerta.
Robustez: logging, reprocessamento e tratamento de erros
A diferença entre um pipeline ETL que funciona em uma demonstração e um que sustenta anos de operação em produção está na robustez. Fontes ficam indisponíveis, arquivos chegam com atraso ou incompletos, redes caem, volumes de dados crescem. Um bom processo de carga pressupõe que algo vai falhar — e está preparado para isso.
Execução robusta de carga: cada etapa é registrada, os commits são feitos após sucesso, erros levam a um rollback controlado e o reprocessamento ocorre a partir do último checkpoint.
Logging completo
Cada execução recebe um batch ID exclusivo. Por meio desse ID, todas as etapas, contagens de linhas, tempos de execução e eventuais erros podem ser associados a uma execução concreta. Essa é a base para monitoramento, diagnóstico de erros e requisitos de auditoria. Em projetos com requisitos rigorosos — como no ambiente bancário e de órgãos públicos — esse registro completo não é opcional, mas obrigatório.
Reprocessamento e idempotência
Um processo de carga deve ser capaz de reiniciar de forma precisa após uma interrupção, sem gravar dados em duplicidade ou deixar lacunas. Isso é alcançado por meio de checkpoints, etapas de carga idempotentes e uma lógica de controle que sabe quais etapas já foram concluídas com sucesso. Em workflows Informatica, desenvolvi uma lógica própria de reprocessamento; no ecossistema Microsoft, baseio-me no controle de batch e em procedimentos transacionalmente seguros.
Controle via PowerShell
Em torno dos processos de carga propriamente ditos, automatizo tarefas operacionais com PowerShell — por exemplo, o deployment de projetos SSDT, o acionamento e monitoramento de execuções ou o preenchimento de relatórios Excel a partir do data warehouse. O exemplo a seguir mostra um wrapper enxuto que invoca um procedimento de carga, verifica o resultado e reage de forma correta em caso de erro.
# Inicia uma execucao ETL, registra o resultado e retorna um
# exit code exclusivo para o scheduler pai (Jenkins/Agent).
param(
[string]$Server = "SQLPROD01",
[string]$Database = "DWH",
[int] $BatchId = (Get-Date -Format "yyyyMMddHHmm")
)
$ErrorActionPreference = "Stop"
try {
Write-Host "[$BatchId] Iniciando execucao ETL em $Server/$Database"
Invoke-Sqlcmd -ServerInstance $Server -Database $Database `
-Query "EXEC etl.RunDailyLoad @BatchId = $BatchId;" `
-QueryTimeout 0 -ErrorAction Stop
$log = Invoke-Sqlcmd -ServerInstance $Server -Database $Database `
-Query "SELECT Status FROM etl.LoadLog WHERE BatchId = $BatchId AND Step='RunDailyLoad';"
if ($log.Status -ne "SUCCESS") {
throw "Execucao ETL $BatchId nao concluida com sucesso: $($log.Status)"
}
Write-Host "[$BatchId] Execucao ETL concluida com sucesso."
exit 0
}
catch {
Write-Error "[$BatchId] Erro: $($_.Exception.Message)"
exit 1 # Scheduler identifica a falha e aciona alerta
}Um exit code claro vale ouro: Jenkins, o SQL Agent ou um cron job identificam de forma confiável se uma execução precisa ser repetida ou escalonada.
Qualidade de dados e testes com tSQLt
Dados em que ninguém confia são inúteis. Por isso, a qualidade de dados faz parte indissociável do desenvolvimento ETL para mim. A qualidade não surge de verificações pontuais, mas de testes automatizados que são executados a cada alteração. No ambiente SQL Server, utilizo o framework tSQLt, com o qual é possível escrever testes funcionais e técnicos diretamente no banco de dados.
Na Agência Federal de Emprego da Alemanha, desenvolvi e aprimorei testes funcionais e testes de regressão com tSQLt e os integrei em um pipeline CI/CD com Jenkins. Isso significa: cada alteração em um procedimento ou em um pacote SSIS é automaticamente verificada contra um conjunto definido de valores esperados antes de avançar para o próximo ambiente.
-- Teste: valores negativos nao devem chegar na tabela de fatos.
EXEC tSQLt.NewTestClass 'SalesTests';
GO
CREATE OR ALTER PROCEDURE SalesTests.[test valores negativos sao filtrados]
AS
BEGIN
-- 1) Isolar dependencias (Fake Table em vez de tabela real)
EXEC tSQLt.FakeTable @TableName = N'stg.SalesOrder';
EXEC tSQLt.FakeTable @TableName = N'core.FactSales';
-- 2) Inserir dados de teste: um registro valido e um invalido
INSERT INTO stg.SalesOrder (OrderId, Amount) VALUES (1, 100.00);
INSERT INTO stg.SalesOrder (OrderId, Amount) VALUES (2, -50.00);
-- 3) Executar a logica a ser testada
EXEC etl.LoadSalesFact @BatchId = 999;
-- 4) Verificar expectativa: somente o registro valido foi carregado
DECLARE @Cnt int = (SELECT COUNT(*) FROM core.FactSales);
EXEC tSQLt.AssertEquals @Expected = 1, @Actual = @Cnt,
@Message = N'Somente valores positivos devem ser carregados.';
END;O tSQLt isola o teste completamente dos dados reais por meio de Fake Tables. O teste é, portanto, reproduzível, rápido e independente do estado atual dos dados.
O verdadeiro ganho dos testes automatizados se manifesta com o tempo. Estruturas de dados, regras de negócio e sistemas de origem mudam; sem testes, cada ajuste se torna um risco, pois ninguém pode afirmar com certeza se uma alteração em um lugar não quebrou algo em outro. Com uma coleção crescente de testes funcionais, essa incerteza se transforma em segurança: se um teste falha após uma alteração, o erro é localizado imediatamente, muito antes de números incorretos aparecerem em um relatório. Essa segurança é a alavanca real que possibilita um desenvolvimento ao mesmo tempo rápido e confiável.
- Verificações de plausibilidade diretamente no processo de carga (intervalos de valores, campos obrigatórios, referências)
- Conciliação de totais entre origem e destino como controle de negócio
- Testes de regressão executados automaticamente a cada alteração
- Anonimização de dados pessoais conforme LGPD como componente ETL fixo
A anonimização merece menção especial: em vários projetos, desenvolvi procedimentos e pacotes SSIS que anonimizam dados pessoais periodicamente e de forma rastreável, em conformidade com a legislação de proteção de dados. É um bom exemplo de que o ETL não apenas movimenta dados, mas também implementa requisitos legais e de negócio.
ELT em nuvem com Azure Data Factory, Synapse e Databricks
Com a nuvem, o ETL clássico evolui cada vez mais para o ELT: os dados são primeiro carregados e transformados posteriormente no sistema de destino, que oferece maior capacidade de processamento. Participei ativamente dessa transformação em vários projetos — como em um prestador têxtil e de serviços, onde construí processos de carga com Azure Synapse e Azure Data Factory e extraí dados para o Databricks em formato Parquet e Delta Lake.
O Azure Data Factory assume a orquestração: pipelines, triggers, parametrização e a conexão com as fontes. O processamento efetivo de grandes volumes de dados ocorre no Synapse ou no Databricks com PySpark. O exemplo PySpark a seguir mostra um processamento incremental típico com Delta Lake, incluindo upsert via MERGE.
# Processamento incremental no Databricks: ler o delta, limpar
# e gravar de forma idempotente na tabela de destino via MERGE.
from pyspark.sql import functions as F
from delta.tables import DeltaTable
# 1) Ler somente registros novos/alterados da camada Bronze
last_wm = spark.sql("SELECT MAX(processed_ts) AS wm FROM ctrl.watermark "
"WHERE entity = 'sales'").collect()[0]["wm"]
bronze = (spark.read.format("delta").table("bronze.sales")
.filter(F.col("modified_ts") > F.lit(last_wm)))
# 2) Limpeza de negocio
silver = (bronze
.filter(F.col("amount") >= 0) # excluir valores negativos
.dropDuplicates(["order_id"]) # deduplicacao
.withColumn("load_date", F.current_date()))
# 3) Upsert idempotente na tabela Silver
target = DeltaTable.forName(spark, "silver.sales")
(target.alias("t")
.merge(silver.alias("s"), "t.order_id = s.order_id")
.whenMatchedUpdateAll()
.whenNotMatchedInsertAll()
.execute())O Delta Lake traz transações ACID para o data lake. O MERGE é idempotente: uma nova execução com os mesmos dados não altera nada — exatamente o comportamento que processos de carga robustos exigem.
Mesmo na nuvem, o princípio permanece: camadas claramente separadas, orquestração centralizada e logging completo — implementados com Azure Data Factory, Synapse e Databricks.
CI/CD, versionamento e deployment
O desenvolvimento moderno de ETL é desenvolvimento de software. Por isso, controle de versão, builds automatizados e deployment controlado fazem parte do meu padrão. Em vários projetos, converti desenvolvimentos existentes de banco de dados e SSIS em soluções SSDT limpas e as coloquei sob controle de versão — com Git em variantes como GitHub, GitLab, Bitbucket e Azure DevOps.
Na Danfoss Power Solutions, migrei pacotes SSIS do SQL Server 2016 para 2022, converti as soluções para o sistema de controle de versão e configurei pipelines Azure DevOps para o build automático. Na Agência Federal de Emprego da Alemanha, aprimorei um pipeline CI/CD com Jenkins no qual os testes tSQLt são executados automaticamente. O exemplo a seguir mostra o núcleo de um pipeline Azure DevOps para um projeto de banco de dados.
# Build e deployment de um projeto de banco de dados SQL (SSDT/DACPAC).
trigger:
branches: { include: [ main ] }
pool:
vmImage: 'windows-latest'
stages:
- stage: Build
jobs:
- job: BuildDacpac
steps:
- task: VSBuild@1
displayName: 'Compilar DACPAC'
inputs:
solution: '**/*.sqlproj'
configuration: 'Release'
- publish: '$(Build.SourcesDirectory)/bin/Release'
artifact: dacpac
- stage: Deploy_Test
dependsOn: Build
jobs:
- deployment: DeployTest
environment: 'DWH-Test'
strategy:
runOnce:
deploy:
steps:
- task: SqlAzureDacpacDeployment@1
displayName: 'Deploy DACPAC para Test'
inputs:
azureSubscription: 'DWH-ServiceConnection'
ServerName: 'sql-test.internal'
DatabaseName: 'DWH'
DacpacFile: '$(Pipeline.Workspace)/dacpac/DWH.dacpac'
AdditionalArguments: '/p:BlockOnPossibleDataLoss=true'O parâmetro BlockOnPossibleDataLoss impede que um deployment automático cause perda acidental de dados. Essas redes de segurança são indispensáveis em pipelines próximos da produção.
Performance e escalabilidade
Performance é um tema recorrente em projetos ETL. Com o crescimento dos volumes de dados, não basta apenas fazer os processos funcionarem — eles precisam caber em uma janela de carga limitada e não podem perturbar a operação. Abordo problemas de performance sempre com medição, não com suposição: planos de execução, estatísticas de espera, logs de tempo de execução e análises de gargalo mostram onde o tempo é efetivamente perdido.
- Processamento baseado em conjuntos em vez de linha a linha (set-based em vez de cursor)
- Carga incremental em vez de Full Loads repetidos
- Indexação adequada e — em tabelas de fatos volumosas — particionamento
- Partition Switching para carga e arquivamento rápidos de grandes volumes de dados
- Redução de movimentação de dados: transformação onde os dados residem
- Paralelização de etapas de carga independentes
Em um projeto de DWH, implementei o particionamento de tabelas grandes com extensão automática das funções de particionamento. Assim, novos períodos podem ser carregados e os antigos arquivados sem comprometer a performance geral. Em outros projetos, a alavanca estava no redesenho de pacotes SSIS existentes e na reescrita de consultas SQL ineficientes — com ganhos de tempo de execução imediatamente perceptíveis.
Para mim, é importante ter uma visão realista sobre performance. Nem todo processo precisa ser o mais rápido possível; o fundamental é que caiba de forma confiável na janela de carga disponível e não perturbe a operação. Uma otimização que reduz um processo de dez para dois minutos só faz sentido se os dez minutos eram um problema real. Por isso, priorizo com base no gargalo real: qual etapa consome a janela de carga, qual consulta gera mais bloqueios, onde ocorre movimentação desnecessária de dados? Essa abordagem direcionada entrega mais do que otimizações genéricas que consomem muito esforço e produzem pouco resultado.
Orquestração e operação
Um pipeline ETL raramente consiste em uma única etapa. Na realidade, dezenas ou centenas de etapas de carga individuais precisam ser executadas na ordem correta, com as dependências corretas e no momento correto. A orquestração é uma disciplina própria. Uma seta de dependência incorreta ou um ponto de reprocessamento esquecido pode paralisar uma execução de carga inteira.
Dependendo do ambiente, utilizo diferentes ferramentas de orquestração. No ecossistema Microsoft clássico, o SQL Server Agent controla os jobs, frequentemente em combinação com pacotes master no SSIS que invocam pacotes subordinados em contêineres definidos. Na nuvem, o Azure Data Factory assume o papel de maestro com pipelines, triggers e atividades. De forma transversal, utilizo o Jenkins como camada de orquestração e automação, especialmente onde o ETL está intimamente integrado ao CI/CD.
Tabelas de controle como espinha dorsal
Independentemente da ferramenta, gosto de trabalhar com tabelas de controle no banco de dados. Elas registram quais etapas existem, em que ordem são executadas, quando foram concluídas com sucesso pela última vez e quais parâmetros uma execução necessita. Essa orquestração orientada a metadados tem uma grande vantagem: novas etapas de carga frequentemente podem ser adicionadas apenas com um registro na tabela de controle, sem necessidade de alterações no código. Isso reduz as fontes de erro e torna a operação transparente.
-- Uma orquestracao enxuta le as proximas etapas de carga a partir de
-- uma tabela de metadados e invoca o procedimento registrado para cada etapa.
DECLARE @Step sysname, @Proc nvarchar(256),
@BatchId bigint = NEXT VALUE FOR etl.BatchSeq;
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT StepName, ProcName
FROM etl.LoadStep
WHERE IsActive = 1
ORDER BY StepOrder;
OPEN cur;
FETCH NEXT FROM cur INTO @Step, @Proc;
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
EXEC etl.WriteLog @BatchId, @Step, N'START';
EXEC sp_executesql @stmt = N'EXEC ' + @Proc + N' @BatchId',
@params = N'@BatchId bigint', @BatchId = @BatchId;
EXEC etl.WriteLog @BatchId, @Step, N'SUCCESS';
END TRY
BEGIN CATCH
EXEC etl.WriteLog @BatchId, @Step, N'ERROR', NULL, ERROR_MESSAGE();
BREAK; -- interromper a execucao de forma controlada; reprocessar a partir desta etapa
END CATCH
FETCH NEXT FROM cur INTO @Step, @Proc;
END;
CLOSE cur; DEALLOCATE cur;A orquestração é intencionalmente simples. Ela registra cada etapa, para de forma controlada em caso de erro e permite um reprocessamento preciso — sem que a ordem esteja codificada de forma rígida no código.
A operação inclui também o monitoramento. Por meio das tabelas de log, é possível construir dashboards que mostram de forma imediata quais execuções foram bem-sucedidas, quanto tempo levaram e onde há problemas. Em um projeto, visualizei esse monitoramento adicionalmente com Grafana; em outros projetos, consultas direcionadas e notificações automáticas em caso de erro foram suficientes.
Abordagem de trabalho
Um bom desenvolvimento ETL não começa com código, mas com compreensão. Antes de construir ou reconstruir um pipeline, adquiro uma visão clara dos sistemas de origem, dos requisitos de negócio e da operação existente. Essa abordagem se consolidou ao longo de muitos projetos e garante que a solução ao final se adapte à realidade da empresa.
- Análise: compreender sistemas de origem, estruturas de dados, regras de negócio e processos existentes
- Conceito: definir arquitetura em camadas, padrões de carga e estratégia de tratamento de erros
- Implementação: desenvolver processos de carga de forma iterativa, com testes e logging desde o início
- Teste e validação: verificação técnica e funcional em conjunto com as áreas de negócio
- Operação: monitoramento, reprocessamento, documentação e melhoria contínua
A estreita colaboração com as áreas de negócio é fundamental para mim. Em muitos projetos — como nas áreas de controladoria, finanças e RH — elaborei requisitos diretamente com as equipes funcionais e os traduzi em soluções técnicas adequadas. Dados não são um fim em si mesmos; eles devem responder a uma pergunta de negócio. Quanto melhor compreendo essa pergunta, melhor será a solução.
Trabalho tanto de forma remota quanto híbrida e presencial, sozinho ou como parte de uma equipe existente. Ao longo dos anos, me especializei em setores muito diversos — setor público, serviços financeiros, indústria, varejo, logística e seguros. Essa diversidade ajuda, pois padrões consolidados de um setor frequentemente podem ser transferidos para outro. Ao mesmo tempo, respeito que cada empresa tem seu próprio ambiente construído ao longo do tempo, suas próprias convenções e suas próprias restrições. Uma solução precisa se adaptar a essa realidade, não a um livro didático.
Serviços típicos em projetos ETL
De acordo com a fase do projeto e as necessidades, assumo diferentes tarefas em torno do desenvolvimento ETL — da análise à implementação e à operação contínua. A seguir, um panorama dos serviços mais frequentes que ofereço em projetos de dados.
- Análise de processos ETL existentes, sistemas de origem e regras de negócio
- Projeto de uma arquitetura ETL em camadas (staging, core, entrega)
- Desenvolvimento de pacotes SSIS e procedimentos de carga T-SQL baseados em conjuntos
- Carga incremental, CDC, SCD2 e historicização
- Migração e modernização de pipelines SSIS e ODI existentes
- ELT em nuvem com Azure Data Factory, Synapse e Databricks
- Qualidade de dados, testes funcionais e testes de regressão com tSQLt
- Anonimização de dados pessoais em conformidade com a LGPD
- CI/CD com Jenkins e Azure DevOps, versionamento com Git
- Análise de performance, otimização e particionamento
- Monitoramento, reprocessamento, tratamento de erros e documentação técnica
Projetos de referência selecionados (anonimizados)
Cliente do setor público
Evolução de um data warehouse existente com SQL Server 2019: ampliação dos procedimentos ETL e pacotes SSIS, camada de importação Data Vault, testes funcionais e de regressão com tSQLt, aprimoramento do pipeline CI/CD com Jenkins, automação com PowerShell e anonimização de dados pessoais.
Empresa industrial
Migração de pacotes SSIS do SQL Server 2016 para 2022, integração ao sistema de controle de versão e configuração de pipelines Azure DevOps para build automático, além de análise dos requisitos para um deployment automatizado em servidores SQL Server on-premises.
Serviços financeiros / banco
Substituição de uma aplicação Java e de um banco de dados Oracle por pipelines SSIS: desenvolvimento de pacotes SSIS para carga de arquivos de texto, projeto de banco de dados para deployment em múltiplos servidores, queries de monitoramento e redesenho com otimização de performance de pacotes existentes.
Fidelização / varejo / clearing
Evolução e estabilização de processos de clearing, migração para uma solução SSDT, introdução do Bitbucket com base Git, desenvolvimento de pacotes SSIS e relatórios SSRS, consultas a APIs REST e OData, anonimização em conformidade com a LGPD e modelos de dados Power BI com segurança em nível de linha.
Prestador têxtil e de serviços
Evolução de um Enterprise Operational Data Store, novos datastores para Vendas e RH, processos de carga para o Dynamics 365 via Azure Synapse, pipelines Azure para orquestração, extração para o Databricks em arquivos Parquet/Delta e medidas de redução de custos no Azure.
Logística / grupo corporativo
Desenvolvimento de processos ETL de DWH para sistemas de bonificação e garantia de qualidade: scripts BTEQ controlados por transação para aquisição de dados, mappings, worklets e workflows Informatica com lógica de reprocessamento, tuning de statements SQL e monitoramento das execuções agendadas.
Perguntas frequentes sobre desenvolvimento ETL
Você trabalha mais com SSIS ou com T-SQL?
Com ambos — e, acima de tudo, com a combinação certa. O SSIS é forte na orquestração e na integração de fontes heterogêneas; o T-SQL é forte em transformações baseadas em conjuntos. Em vários projetos, substituí fluxos de dados SSIS que operavam linha a linha por lógica T-SQL baseada em conjuntos, melhorando substancialmente o tempo de execução e a estabilidade.
Você pode assumir e modernizar pipelines ETL existentes?
Sim. Grande parte dos meus projetos consiste na assunção, estabilização e modernização de processos de carga existentes — incluindo versionamento, testes, migração para novas versões do SQL Server e migração gradual para a nuvem.
Como você garante que os dados estão corretos?
Por meio de verificações de plausibilidade integradas, conciliação de totais entre origem e destino e, principalmente, por testes funcionais automatizados e testes de regressão com tSQLt, integrados ao pipeline CI/CD.
Você também apoia ETL em nuvem ou ELT?
Sim. Construí processos de carga com Azure Data Factory, Azure Synapse e Databricks, extraí dados em formato Parquet e Delta Lake e me preocupei deliberadamente com o controle de custos.
Como você trata dados pessoais?
A anonimização em conformidade com a LGPD é um componente ETL fixo em vários dos meus projetos. Desenvolvi procedimentos e pacotes SSIS que anonimizam dados pessoais de forma periódica e rastreável.
Em quais idiomas podemos trabalhar juntos?
Em português, alemão e inglês — todos fluentes, inclusive em discussões técnicas e de negócio.