Para melhorar o desempenho de consultas e reduzir a possibilidade de deadlocks em tabelas é indicada a utilização de níveis de isolamento.
O operador NOLOCK é bastante empregado em queries SQL para ignorar os locks das tabelas e lê-las diretamente. Assim, ignorando o sistema de bloqueios, a performance de consultas é maior e não se corre o risco das operações ficarem “em espera”, aguardo o fim das transações.
O comando NOLOCK não é suportado pelo Entity Framework, isto é, não existe um meio de “ligar ou desligar” o seu uso. Mas podemos alterar o nível de isolamento das transações, o que “no fim das contas”, gera os mesmos resultados. No exemplo abaixo é apresentada essa prática, onde o nível de isolamento da transação é alterado.
ReadCommitted Os processos de leitura ficam em espera caso existam outras transações de atualização em uma mesma tabela.
ReadUncommitted Não respeita os bloqueios exclusivos das transações permitindo a leitura de dados ainda não commitados. O fato de que dados não commitados possam ser lidos é chamado de "Leitura suja".
Snapshot Respeita os bloqueios das transações, mas os processos de leitura não ficam em espera. Os processos de leitura retornam apenas dados comitados, pois é criada uma versão do dados que possa ser lida enquanto os demais são modificados.
Existem outros níveis de isolamento que podem ser encontrados nessa enumeração. Você pode encontrar mais detalhes sobre os níveis de isolamento disponíveis por meio desse link: http://msdn.microsoft.com/pt-br/library/system.data.isolationlevel(v=vs.90).aspx
Essa é a dica mais simples: use cache. Sempre que possível faça cache dos seus dados. Aqueles dados que não sofrem alterações constantes e que sempre são requisitados são fortes candidatos a serem mantidos em cache. Esse é o tipo de decisão simples de ser tomada e implementada, cujo resultado pode salvar recursos do servidor de banco de dados e tornar a aplicação mais rápida.
Mas, para padronizarmos o tipo de Loading do EF (se é que isso é bom), não seria legal desabilitar o Lazy Loading e forçar que toda a consulta realmente traga todo o dado necessário? O custo/benefício que pederemos não será tão afetado não?
Acredito que não existe perda, pois ao executar um menor número de consultas acabamos por economizar recursos de ambos servidores, visto que de qualquer forma todas as consultas trariam a mesma quantidade de dados.
Gostei muito da número 5. Parece ser a mais simples e que muita gente não presta atenção. Depois tem 1 zilhão de requisições de bobeira.
Trabalho com aplicação Winforms e EF5. No começo tentei carregar os contextos apenas quando eram utilizados, com o comando USING. Porém começou a dar muito trabalho fazer sempre o “ATTACH” das propriedades. Em telas onde eu tinha vários relacionamentos 1-N para a mesma entidade, o método de salvar ficava gigantesco.
No final, optamos por abrir o contexto quando a tela abre e manter ele até o formulário ser fechado. Trabalhando com UnitOfWork acesso todas as tabelas por meio do mesmo contexto e como elas vem do mesmo lugar, não preciso “atachar” tudo depois quando salvar.
O maior problema, como você mesmo comentou, é o risco que temos de estar trabalhando com dados desatualizados.
A sorte é que vc trabalha em uma aplicação WinForms e consegue controlar essas instâncias em memória. Se fosse uma aplicação Web isso seria bem mais complicado.