Estou fazendo uma atualização em lote onde processo os registros sequencialmente (Usuário 1, Usuário 2 etc.). Cada registro possui diversas consultas de atualização associadas a ele. Preciso pular se houver um problema de dados para um registro individual (usuário neste caso). Idealmente, gostaria de processá-los em paralelo, mas ainda não atingi esse nível (muitos desafios).
É possível fazer isso de forma que:
- Existe uma única transação.
- Se houver uma falha, as instruções associadas a esse registro serão revertidas, sem afetar outras.
- Comprometer-se.
Por exemplo, tenho 4 usuários em um arquivo CSV. Se 3 forem bons e 1 for ruim, 3 deverão ser confirmados (ou abortados) atomicamente; 1 deve ser ignorado com erros.
Observado:
do everything for user 1;
do everything for user 2;
--> if there is failure, it rolls back the *entire* transaction
do everything for user 3;
Na verdade, qualquer nível de erro >= 16 está revertendo toda a transação.
Esperado:
do everything for user 1;
do everything for user 2;
--> if there is failure, roll back this *block* only
do everything for user 3;
do everything for user 4;
É um try-catch
requisito normal em qualquer linguagem de programação; no entanto, não foi possível ver um equivalente do SQL Server (envolvendo transações). Eu li sobre pontos de verificação, mas não tenho certeza se essa é uma opção a ser considerada.
Não é possível confirmar algumas partes de uma transação e reverter outras. Isso anularia o objetivo de uma transação: tudo dentro da transação é bem-sucedido ou falha como uma unidade. Em outras palavras, uma transação é atômica.
Parece que você não deseja uma transação para todo o processo. Isso significaria que todos os registros foram processados com sucesso ou nenhum foi. Qualquer erro garantiria que o banco de dados persistente retornasse ao estado em que estava antes de qualquer alteração ocorrer.
Pela sua descrição, parece que você deveria iniciar uma nova transação para cada usuário .
Execute todas as alterações necessárias para esse usuário e, em seguida, confirme ou reverta, dependendo se alguma condição de erro fatal foi encontrada. Você pode querer incluir um número limitado de novas tentativas para erros transitórios (resolvíveis), como um impasse. Ou registre-os em algum lugar para tentar novamente mais tarde.
Esse arranjo levaria ao resultado que você indica: usuários sem erros são bem-sucedidos, usuários com erros têm todas as alterações desfeitas.
Idealmente, você também escreveria sua rotina para reiniciar do ponto de falha em caso de desastre. Isso evita o reprocessamento de dados do usuário que já foram processados com êxito no banco de dados quando ocorreu a falha.
Para obter um guia completo, consulte Tratamento de erros e transações no SQL Server, de Erland Sommarskog.
A mudança na execução de uma transação por usuário pode afetar o desempenho. Se você percebe isso depende de quanto trabalho é realizado por usuário e de outros fatores.
Lembre-se de que cada instrução seria executada em sua própria transação de confirmação automática se você não estivesse usando uma transação explícita.
Se isso for um fator importante em sua situação específica, você pode usar durabilidade atrasada , melhorar o log do sistema ou executar o processo em mais de um thread, por exemplo.
Você não precisa necessariamente escrever tudo isso sozinho. Existem muitas ferramentas e tecnologias para ler dados de entrada CSV e canalizar essas alterações para um banco de dados, talvez em paralelo. Por exemplo, SSIS, Azure Data Factory e Synapse Pipelines.
Sinta-se à vontade para fazer perguntas de acompanhamento separadas, conforme necessário.