Eu tenho um pedaço de código que executa inserções em tabelas altamente desnormalizadas. As tabelas têm números de colunas variando de ~100 a 300+. Este é o SQL Server 2008 R2, rodando no Windows Server 2008.
Cada inserção consiste na inserção de um número de tabelas na mesma transação. Algumas inserções são agrupadas pelo NHibernate, mas outras não, mas estão todas sob a mesma transação.
Quando executo inserções, digamos, 500 vezes, chamando repetidamente um trecho de código que executa a inserção, obtenho uma média de ~ 360 ms.
O estranho é que, quando executo o código de teste simultaneamente usando 4 processos (o mesmo exe executado em 4 prompts de comando diferentes no Windows Server 2008), o desempenho de inserção por chamada fica muito melhor. Vejo rajadas que chegam a 90 ms (quase X4 mais rápido). Estou medindo o tempo de inserção do código.
Como os 4 processos não sabem nada um sobre o outro, presumo que isso tenha algo a ver com o SQL Server, mas não tenho a menor ideia do porquê. Gostaria de saber porque isso está acontecendo e se existe alguma configuração que me permita obter a mesma performance quando os inserts não são tão frequentes.
Sugestões relacionadas aos métodos de monitoramento do SQL Server para entender o que está acontecendo no nível do banco de dados são igualmente bem-vindas.
Uma razão possível é que quatro processos simultâneos geram um padrão mais favorável de descargas de log - geralmente significando que cada descarga de log grava mais dados do que no caso de um único processo em execução.
Para determinar se o tamanho da taxa de transferência/liberação do log de transações é um fator, monitore:
WRITELOG
eLOGBUFFER
esperaProcure limites internos sendo atingidos. No SQL Server 2008 R2, pode haver no máximo 32 E/Ss de liberação de log pendentes (assíncronas) por banco de dados em versões de 64 bits (somente 8 em 32 bits). Há também um limite de tamanho total nos IOs pendentes de 3840 KB.
Mais informações e leitura adicional:
Tudo o que @PaulWhite diz, mais...
Se você tiver chaves estrangeiras, cada inserção exigirá que uma verificação seja feita em cada tabela referenciada. Parece-me que você está, já que está recebendo apenas 360 ms, o que parece lento para mim.
De qualquer forma, a verificação dessas tabelas é bastante ajudada por ter esses dados já na RAM, em vez de carregá-los no disco.
Parece-me que carregar os dados na RAM é uma parte significativa da sua execução e que só precisa acontecer uma vez.
Também pode ser um cache de plano eficaz e que suas consultas precisam ser compiladas na primeira vez, com chamadas subsequentes podendo evitar essa fase.
alguns servidores / cpus / sistemas operacionais lembram os padrões. como cache.
Como você está fazendo a mesma coisa 4 vezes, tenho certeza de que existem maneiras de economizar. O que estou supondo é que a primeira maneira de fazer isso é considerada um processo longo (exemplo 1), mas na segunda maneira é ver o código reutilizado e executá-lo como cache (exemplo2) ou pode ser que o primeiro processo seja grande demais para caber tudo no (exemplo ram3).
exemplo1: 011111000011011111000011110111110000111110111110000
exemplo2: 0111110000|11|0111110000|111|0111110000|1111|0111110000
exemplo3: 0111110000011111000001111100000111110000 exemplo3: loop: 0111110000
Eu sei que o servidor ubuntu faz isso com consultas mysql repetidas. Posso salvá-los em cache, embora realmente a única diferença de tempo seja de 10 a 40 mm, mas isso aumenta. Quando eu estava na escola havia aulas que mostravam que você tem que fazer programas (perl/php) usarem esse cache para serem mais rápidos.
Mas, pode depender do programa, em que linguagem é, em que foi compilado ou como foi programado.