Estou tentando otimizar um pacote SSIS que recupera dados de uma tabela de transações muito grande que obtém milhões de novos registros diariamente. Os dados estão sendo coletados de várias centenas de servidores de campo nos quais o SQL Server 2008 Standard Edition está instalado. CDC, portanto, não pode ser usado porque é um recurso Enterprise. O plano é este:
- Coluna de arquivo, smallint - 0=novo (restrição padrão), 1=arquivado, 2=atualizado (acionador)
- Restrição padrão Arquivo=0
- Arquivo do acionador de atualização=2
- Índice no arquivo, carimbo de data/hora
O pacote SSIS irá obter todos os registros onde Archive=0, inseri-los no destino, obter todos os registros onde Archive=2 e atualizá-los no destino.
O que preciso de ajuda é a configuração da coluna Arquivo como 1 após o procedimento do SSIS terminar de gravar linhas novas ou atualizadas. Qual seria a maneira mais eficiente de definir todas as linhas processadas sem tocar em nenhuma linha que possa ter sido inserida ou atualizada após a seleção inicial?
Como você está usando o SSIS e capturando as linhas alteradas, você deve fazer com que o SSIS capture os valores PK para as linhas que estão sendo processadas. A última etapa do pacote deve ser fazer uma atualização direcionada na tabela de origem, definindo o
[Archive]
campo como 1 com base nesses valores de PK.E se ainda não tiver feito, o acionador de atualização precisa excluir essas alterações da configuração do
[Archive]
campo como 2. Você provavelmente precisará de algo como:MAS, então você precisa lidar com o cenário em que uma linha é atualizada durante o processo ETL. Você ainda deseja ETL que muda na próxima vez. Mas se o processo ETL estiver em execução, ele mudará o
[Archive]
campo para 1 no final e não haverá registro dessa linha sendo alterada. Então você precisa de outro valor para indicar "Being ETLed", talvez 3. Você pode então, semelhante ao que @billinkc sugeriu em um comentário sobre a questão, faça umUPDATE
com aOUTPUT
cláusula da seguinte forma:Então, na etapa final do pacote SSIS, a atualização de destino deve estar em ambos os valores PK
AND [Archive] = 3
. E adicione3
àIN
lista na consulta de atualização do acionador acima. Dessa forma, apenas os registros que não foram alterados durante o processo ETL serão atualizados para1
, enquanto os registros que foram alterados durante o ETL aparecerão como2
e serão selecionados novamente na próxima vez com seus valores modificados.Claro, você também pode querer criar um índice filtrado no
[Archive]
campo para suportar a obtenção de registros marcados como 0, 2 ou 3. Portanto:Você deseja obter os registros marcados como
3
porque, supondo que seja um thread único por servidor de campo, os registros marcados como3
representam registros travados devido a um processo anterior que falhou. É também por isso que você não deseja marcar os registros como quando1
osUPDATE...OUTPUT
obteve inicialmente; se o processo falhar, eles serão marcados como já arquivados e não serão recuperados.Dito isso, talvez seja melhor usar uma tabela de filas em vez de um campo de status. Você pode criar uma tabela simples com apenas alguns campos:
Em seguida, o gatilho se torna um
INSERT, UPDATE
gatilho simples que apenas faz:Em seguida, o processo SSIS obtém os valores por meio de:
E o final do processo SSIS faz uma exclusão simples na
[MyTableEtlQueue]
tabela com base nos[QueueID]
valores extraídos no início.Nesse modelo, você não precisa do índice filtrado ou da coluna de status em uma tabela grande, o que reduz a contenção e o tamanho dessa tabela já grande. Você não precisa se preocupar com registros em trânsito, seja em termos de atualizações ou falhas de processo.
EDIT:
Dada a nova informação da tabela de origem que não possui exclusividade, isso requer apenas uma pequena alteração neste método da tabela de filas: em vez de rastrear apenas o PKfield (que aparentemente não existe ;-), rastreie todos os campos ( ou pelo menos tudo o que precisa ser ETLed).
Portanto, a tabela de filas muda para:
E o gatilho muda para:
Em seguida, o processo SSIS muda para ser (observe a falta de JOIN na tabela de origem agora):
Esse método de tabela de fila isola a tabela de origem (e seu processamento) do processo de auditoria/ETL (muito parecido com o que o CDC faz). Isso permite que seu aplicativo interaja com a tabela de origem sem problemas, e nenhuma nova coluna que ocupe mais espaço na página de dados, e nenhuma transação potencialmente longa segurando a tabela de origem enquanto o ETL processa.
Que tal fazer uso da mesa virtual OUTPUT ? Defina corretamente o nível de isolamento da transação (instantâneo/serializável) para que você só veja as linhas a partir do momento em que seu processo é iniciado.
Use o seguinte para sua fonte OLE DB
Isso atualiza tudo em uma boa operação atômica com um efeito colateral de gerar a saída de destino em seus buffers de fluxo de dados. Encaminhe isso para o seu destino e pronto. Agradável e arrumado
O Change Tracking (CT) e o Change Data Capture (CDC) são integrados ao SQL Server. O CT pode identificar as linhas que mudaram desde a última vez que você perguntou. O CDC pode fornecer um histórico completo de todas as alterações de dados desde a última vez que você perguntou. Ambos são facilmente manipulados a partir do SSIS.
Não haverá necessidade de redefinir sinalizadores por linha após o processamento. O sistema lida com tudo isso por meio de tabelas ocultas adicionais especificamente para essa finalidade.
Uma solução SSIS pura seria entregar os Fluxos de Dados para as tarefas Inserir e Atualizar nas Transformações de Cache.
http://msdn.microsoft.com/en-us/library/bb895264.aspx
Se eles ocorrerem em 1 fluxo de dados, você poderá enviá-los para um único cache, caso contrário, você precisará de 2.
Em seguida, você pode testar esses Caches em Fluxos de Dados posteriores usando a transformação de Pesquisa. Eu redirecionaria todas as linhas correspondentes para descartá-las efetivamente e, em seguida, continuaria apenas com as linhas não correspondentes.
Nota Os caches são armazenados na memória, então tente manter o conteúdo enxuto, por exemplo, apenas a(s) coluna(s) chave. Contanto que você não esgote a memória física, o desempenho do tempo de execução será muito rápido (sem E/S).
Essa solução é provavelmente a mais simples de construir e testar, pois não precisa de código para ser implementada.