Problema-chave
A latência que estamos experimentando não está aplicando as alterações do Distribuidor aos Assinantes (se observarmos o Replication Monitor, a latência geralmente é <1 segundo), é o tempo que uma transação confirmada no banco de dados do publicador leva para chegar ao distribuidor .
Parte do problema é que temos vários filtros aplicados a uma de nossas tabelas mais voláteis e, a cada atualização/inserção/exclusão, o LogReader.exe precisa verificar em qual publicação colocar esse registro com base nos filtros aplicados.
Pelos testes que fizemos parece que cada filtro adicional aplicado pode aumentar exponencialmente o tempo que o LogReader leva para processar cada transação.
( editar 23/06/2011: adicionado mais detalhes sobre os filtros )
Fundo
Em nosso setup de Replicação temos diversas publicações com filtros em uma tabela altamente volátil (média de 1,5 milhões de transações em um período de 2h). Durante períodos pesados, isso pode resultar na execução do LogReader em uma latência de 20 segundos (geralmente < 1 segundo)
Identificamos várias áreas de melhoria (reduzindo o número de filtros, reduzindo o número de atualizações, eliminando o processamento etc.). Uma área potencial de melhoria é mudar a forma como as atualizações são aplicadas.
Uma tabela de exemplo (para ajudar na explicação)
myTable
----------------
myID int
myGroupID1 int
myGroupID2 int
Suspended bit
FilterFlag1 int
FilterFlag2 int
FilterFlag3 int
Para replicação para ilustrar isso, teríamos 5 publicações de [myTable] :
Publication Filter
----------- ------
NoFilter1 [all records]*
NoFilter2 [all records]*
Filter1 FilterFlag1 = 1
Filter2 FilterFlag2 = 1
Filter3 FilterFlag1 = 1 AND FilterFlag2 = 1
- Outras tabelas são combinadas nessas publicações e é por isso que a mesma tabela com filtros idênticos (nenhum) está em mais de uma publicação.
Processo de atualização atual
A maioria dos aplicativos que atualizam essa tabela faz isso percorrendo sua coleção de objetos, aplicando a alteração a esse único objeto e, em seguida, confirmando sua alteração no banco de dados antes de passar para o próximo objeto.
De uma perspectiva de rastreamento de banco de dados, isso significa que obtemos até 120 instruções de atualização quando a alteração ocorre
Exemplo
update [myTable] set Suspended = @Suspended
where myID = @pID
Processo de atualização proposto
Como as coleções de objetos são realmente baseadas nos IDs do grupo, uma melhoria potencial é fazer uma atualização em massa (em vez de atualizações individuais) e, em seguida, atualizar a coleção de objetos. Reduzindo o número de instruções de atualização para 1 ou 2 (dependendo dos cenários de negócios).
Exemplo
update [myTable] set Suspended = @Suspended
where myGroupID1 = @groupID1
and myGroupID1 = @groupID2
Impacto no LogReader?
Do ponto de vista do processamento do aplicativo, fazer uma única atualização faz sentido para mim (menos idas e voltas entre o aplicativo e o banco de dados = mais rápido), porém não tenho certeza de como o LogReader tratará os dois cenários, pois precisa processar cada registro atualizado por a transação..
O LogReader processará esses registros mais rapidamente ou mais lentamente em uma atualização em massa?
Nos registros de log, essas são instruções separadas que são gravadas no log. O leitor de log então os agruparia e os executaria como uma única transação no banco de dados.
Se seu banco de dados usa procedimentos armazenados, você pode replicar os procedimentos armazenados, o que permitiria que a chamada do procedimento armazenado fosse replicada em vez das atualizações de dados reais.