Minha empresa usa um aplicativo que apresenta problemas de desempenho bastante importantes. Há vários problemas no banco de dados em que estou trabalhando, mas muitos deles são puramente relacionados ao aplicativo.
Na minha investigação, descobri que existem milhões de consultas no banco de dados do SQL Server que consultam tabelas vazias. Temos cerca de 300 tabelas vazias e algumas dessas tabelas são consultadas até 100-200 vezes por minuto. As tabelas não têm nada a ver com nossa área de negócios e são essencialmente partes do aplicativo original que o fornecedor não removeu quando elas foram contratadas pela minha empresa para produzir uma solução de software para nós.
Além do fato de suspeitarmos que nosso log de erros do aplicativo está sendo inundado por erros relacionados a esse problema, o fornecedor garante que não há impacto no desempenho ou na estabilidade do aplicativo ou do servidor de banco de dados. O log de erros é inundado na medida em que não podemos ver mais de 2 minutos de erros para fazer diagnósticos.
O custo real dessas consultas obviamente será baixo em termos de ciclos de CPU, etc. Mas alguém pode sugerir qual seria o efeito no SQL Server e no aplicativo? Eu suspeitaria que a mecânica real de enviar uma solicitação, confirmá-la, processá-la, devolvê-la e confirmar o recebimento pelo aplicativo teria um impacto no desempenho.
Usamos o SQL Server 2008 R2, Oracle Weblogic 11g para o aplicativo.
@ Frisbee- Para encurtar a história, criei uma tabela contendo o texto da consulta que atingiu as tabelas vazias no banco de dados do aplicativo e, em seguida, consultei todos os nomes de tabela que eu sei que estão vazios e recebi uma lista muito longa. O maior sucesso foi em 2,7 milhões de execuções em 30 dias de atividade, tendo em mente que o aplicativo geralmente está em uso das 8 às 18 horas, para que esses números sejam mais concentrados nas horas operacionais. Múltiplas tabelas, várias consultas, provavelmente algumas relavent via junções, outras não. O maior sucesso (2,7 milhões na época) foi uma simples seleção de uma única tabela vazia com uma cláusula where, sem junções. Eu esperaria que consultas maiores com junções às tabelas vazias incluíssem atualizações nas tabelas vinculadas, mas vou verificar isso e atualizar esta pergunta o mais rápido possível.
Atualização: existem 1000 consultas com uma contagem de execução entre 1043 - 4622614 (mais de 2,5 meses). Vou ter que cavar mais para descobrir quando o plano em cache se origina. Isso é apenas para lhe dar uma idéia da extensão das consultas. A maioria é razoavelmente complexa, com mais de 20 junções.
@ srutzky- sim, acredito que exista uma coluna de data relacionada a quando o plano foi compilado, para que seja de seu interesse, por isso vou verificar. Gostaria de saber se os limites de encadeamento seriam um fator quando o SQL Server estiver em um cluster VMware? Em breve será um Dell PE 730xD dedicado, felizmente.
@Frisbee - Desculpe pela resposta tardia. Como você sugeriu, eu executei um select * da tabela vazia 10.000 vezes em 24 threads usando o SQLQueryStress (na verdade, 240.000 iterações) e atingi 10.000 solicitações em lote / s imediatamente. Reduzi para 1000 vezes mais de 24 threads e atingi pouco menos de 4.000 solicitações em lote / s. Eu também tentei 10.000 iterações em apenas 12 threads (so 120000 iterações totais) e isso produziu 6.505 lotes / s sustentados. O efeito na CPU foi realmente perceptível, em torno de 5 a 10% do uso total da CPU durante cada execução de teste. As esperas na rede eram insignificantes (como 3ms com o cliente na minha estação de trabalho), mas o impacto na CPU estava lá, com certeza, o que é bastante conclusivo para mim. Parece resumir-se ao uso da CPU e um pouco de E / S desnecessária de arquivo de banco de dados. O total de execuções / segundo funciona em pouco menos de 3000, que é mais do que em produção, no entanto, estou testando apenas uma das dezenas de consultas como essa. O efeito líquido de centenas de consultas atingindo tabelas vazias a uma taxa entre 300-4000 vezes por minuto, portanto, não seria desprezível no que diz respeito ao tempo da CPU. Todos os testes foram feitos em um PE 730xD inativo com matriz de flash duplo e 256 GB de RAM, 12 núcleos modernos.
@ srutzky- bom pensamento. O SQLQueryStress parece usar o pool de conexões por padrão, mas eu dei uma olhada de qualquer maneira e descobri que sim, a caixa de pool de conexões está marcada. Atualize para seguir
@ srutzky- O pool de conexões aparentemente não está ativado no aplicativo - ou, se estiver, não está funcionando. Fiz um rastreamento do criador de perfil e descobri que as conexões têm EventSubClass "1 - Não em pool" para eventos de Logon de Auditoria.
RE: Pool de conexões - Verificou os weblogics e encontrou o pool de conexões ativado. Executou mais rastreamentos contra sinais ao vivo e encontrou que o pool não está ocorrendo corretamente / de modo algum:
E aqui está o que parece quando executo uma única consulta sem junções em uma tabela preenchida; as exceções exibem "Ocorreu um erro relacionado à rede ou à instância ao estabelecer uma conexão com o SQL Server. O servidor não foi encontrado ou não estava acessível. Verifique se o nome da instância está correto e se o SQL Server está configurado para permitir conexões remotas. (provedor: provedor de pipes nomeados, erro: 40 - Não foi possível abrir uma conexão com o SQL Server) "Observe o contador de solicitações em lote. Executar ping no servidor durante o tempo em que as exceções são geradas resulta em uma resposta de ping bem-sucedida.
Atualização - duas execuções de teste consecutivas, mesma carga de trabalho (selecione * deEmptyTable), pool ativado / não ativado. Um pouco mais de uso da CPU e muitas falhas e nunca ultrapassa 500 solicitações em lote / s. Os testes mostram 10.000 lotes / s e nenhuma falha com o pool LIGADO, e cerca de 400 lotes / s, em seguida, muitas falhas devido à desativação do pool. Gostaria de saber se essas falhas estão relacionadas à falta de disponibilidade de conexão?
@ srutzky- Selecione Contagem (*) em sys.dm_exec_connections;
Pool ativado: 37 de forma consistente, mesmo após o teste de carga ser interrompido
Pool desabilitado: 11-37, dependendo da ocorrência ou não de exceções
no SQLQueryStress, isto é: quando essas calhas aparecem no
gráfico Lotes / s, as exceções ocorrem no SQLQueryStress e o
número de conexões cai para 11 e, em seguida, volta gradualmente para 37 quando os lotes começam a atingir o pico e as exceções não estão ocorrendo. Muito, muito interessante.
O número máximo de conexões nas instâncias de teste / ao vivo é definido como o padrão 0.
Verificamos os logs do aplicativo e não conseguimos encontrar problemas de conectividade, no entanto, existem apenas alguns minutos disponíveis devido ao grande número e tamanho de erros, ou seja: muitos erros de rastreamento de pilha. Um colega no suporte a aplicativos recomenda que ocorra um número substancial de erros de HTTP relacionados à conectividade. Parece que, por algum motivo, o aplicativo não está agrupando corretamente as conexões e, como resultado, o servidor está ficando repetidamente sem conexões. Vou examinar mais os logs de aplicativos. Gostaria de saber se existe uma maneira de provar que isso está acontecendo na produção do lado do SQL Server?
@ srutzky- Obrigado. Amanhã vou verificar a configuração da weblogic e atualizar. Eu estava pensando sobre as meras 37 conexões - se SQLQueryStress está executando 12 threads em 10.000 iterações = 120.000 instruções de seleção sem pool, isso não significa que cada seleção cria uma conexão distinta com a instância sql?
@ srutzky- Weblogics estão configurados para agrupar conexões, então deve estar funcionando bem. O pool de conexões é configurado assim, em cada um dos 4 weblogics com balanceamento de carga:
- Capacidade inicial: 10
- Capacidade máxima: 50
- Capacidade mínima: 5
Quando eu aumento o número de threads executando a consulta de seleção de tabela vazia, o número de conexões atinge um pico em torno de 47. Com o pool de conexões desabilitado, vejo consistentemente um número máximo de solicitações em lote / segundo mais baixo (de 10.000 para cerca de 400). O que acontece sempre é que as 'exceções' no SQLQueryStress ocorrem logo após os lotes / s entrarem em um vale. Está relacionado à conectividade, mas não consigo entender exatamente por que isso está acontecendo. Quando nenhum teste está sendo executado, #connections cai para cerca de 12.
Com o pool de conexões desabilitado, estou tendo problemas para entender por que as exceções ocorrem, mas talvez seja uma questão totalmente diferente de stackExchange / Adam Machanic?
@srutzky Gostaria de saber então por que as exceções ocorrem sem o pool ativado, mesmo que o SQL Server não esteja ficando sem conexões?
SELECT COUNT(*) FROM sys.dm_exec_connections;
para verificar se o valor é muito diferente entre ter o pool ativado ou não. Com base nesses erros, acho que haveria muito mais conexões quando o pool estiver desativado.Pooling=false
ouMax Pool Size
?Respostas:
Sim, e existem até alguns fatores adicionais, mas é impossível afirmar em que grau algum deles está afetando seu sistema sem analisá-lo.
Dito isto, você está perguntando o que poderia ser um problema e há algumas coisas a serem mencionadas, mesmo que algumas delas não sejam atualmente um fator em sua situação específica. Você diz que:
Pode até haver mais, mas isso deve ajudar a entender as coisas. E lembre-se de que, como a maioria dos problemas de desempenho, é tudo uma questão de escala. Todos os itens mencionados acima não são problemas se forem atingidos uma vez por minuto. É como testar uma alteração em sua estação de trabalho ou no banco de dados de desenvolvimento: ele sempre funciona com apenas 10 - 100 linhas nas tabelas. Mova esse código para produção e leva 10 minutos para ser executado, e alguém é obrigado a dizer: "bem, funciona na minha caixa" ;-). Ou seja, é apenas devido ao grande volume de chamadas que você está vendo um problema, mas essa é a situação que existe.
Portanto, mesmo com 1 milhão de consultas inúteis, 0 linhas, isso equivale a:
mais conexões sendo mantidas que ocupam mais memória. Quanta RAM física não utilizada você possui? essa memória seria melhor usada para executar consultas e / ou cache do plano de consultas. Na pior das hipóteses, você está sem memória física e o SQL Server precisa começar a usar a memória virtual (swap), pois isso diminui a velocidade (verifique o log de erros do SQL Server para ver se você está recebendo mensagens sobre a paginação de memória).
E apenas no caso de alguém mencionar "bem, existe um pool de conexões". Sim, isso definitivamente ajuda a reduzir o número de conexões necessárias. Porém, com consultas chegando até 200 vezes por minuto, ainda há muita atividade e conexões simultâneas para as solicitações legítimas. Faça um
SELECT * FROM sys.dm_exec_connections;
para ver quantas conexões ativas você está mantendo.Se não estou incorreto sobre o que venho declarando aqui, parece-me que, mesmo em pequena escala, esse é um tipo de ataque DDoS ao seu sistema, pois está inundando a rede e o SQL Server com solicitações falsas. , impedindo que solicitações reais cheguem ao SQL Server ou sejam processadas pelo SQL Server.
fonte
Se as tabelas são atingidas 100-200 vezes por minuto, elas estão (espero) na memória. A carga no servidor é muito, muito baixa. A menos que você tenha alta CPU ou memória no servidor de banco de dados, isso provavelmente não é um problema.
Sim, as consultas usam bloqueios compartilhados, mas esperamos que não estejam bloqueando nenhum bloqueio de atualização nem bloqueados por nenhum bloqueio de atualização. Você tem alguma atualização, inserção ou exclusão nessas tabelas. Caso contrário, eu simplesmente deixaria para lá - se você está tendo problemas de desempenho, deve haver peixes maiores para fritar do ponto de vista do servidor de banco de dados.
Fiz um teste em 100.000 contagens de seleção (*) em uma tabela vazia e ela foi executada em 32 segundos e as consultas foram realizadas em uma rede. Então 1/3 milissegundo. A menos que sua rede esteja sobrecarregada, isso não afeta o cliente. Se você estiver tendo problemas importantes de desempenho, essas consultas em branco de 1/3 milissegundos não serão o que está matando o aplicativo.
E isso pode ser apenas parte de uma junção esquerda, capturando alguns dados estáticos do tipo que não faz parte do aplicativo atual. Pode ser encadeado com outras consultas, portanto não é uma viagem de ida e volta extra. Se sim, é desleixado, mas não está causando mais tráfego.
Então, voltemos a ver as declarações reais. Você está vendo alguma atualização, adição ou exclusão nessas tabelas?
Sim, muitas tabelas e consultas vazias para tabelas vazias são indicação de codificação incorreta. Mas se você estiver tendo problemas importantes de desempenho, essa não é a causa, a menos que você também tenha algumas operações de gravação realmente desleixadas nessas tabelas.
fonte
Em geral, em cada consulta, são executadas as seguintes etapas:
muitas consultas mencionadas podem causar carga extra em um sistema que já é pesado - carga extra em conexões, CPU, RAM e E / S.
fonte