Estou lidando com problemas de desempenho com um aplicativo do Windows que usa o SQL Server Express (2014) no back-end.
Consegui fazer isso funcionar muito melhor, principalmente revisando o lado da indexação do SQL Server, mas há um relatório específico que ainda está sendo executado muito lentamente.
Olhando para o que está fazendo, parece estar fazendo um loop no aplicativo e consultando milhares de SELECT *
consultas muito simples em uma tabela WHERE = Primary Key
, recuperando apenas um registro em cada caso. E quando digo IDÊNTICO, quero dizer idêntico, não está nem variando a chave primária para obter coisas diferentes, está pedindo exatamente o mesmo registro de volta do banco de dados aparentemente cada vez que precisa, até cem vezes em apenas alguns segundos.
Este é um relatório de exemplo que leva cerca de 10 a 15 segundos para ser executado quando o servidor está silencioso - quantas vezes a consulta é executada, adicionei como um comentário:
SELECT * FROM "Patient" WHERE "_Recno" = 35051 -- (runs 106 times)
SELECT * FROM "Client" WHERE "_Recno" = 15607 -- (99 times)
SELECT * FROM "SpeciesEntry" WHERE "_Recno" = 180 -- (97)
SELECT * FROM "Table" WHERE "_Recno" = 9 -- (97)
SELECT * FROM "DefaultEntry" WHERE "_Recno" = 2615 -- (96)
SELECT * FROM "Table" WHERE "_Recno" = 34 -- (96)
SELECT * FROM "DefaultEntry" WHERE "_Recno" = 2562 -- (84)
SELECT * FROM "Table" WHERE "_Recno" = 33 -- (84)
SELECT * FROM "Treatment" WHERE "_Recno" = 1682 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 1819 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 927 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 934 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 935 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 940 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 942 -- (33)
SELECT * FROM "Treatment" WHERE "_Recno" = 944 -- (33)
SELECT * FROM "OptionWP" WHERE "_Recno" = 103 -- (3)
SELECT * FROM "OptionWP" WHERE "_Recno" = 54 -- (1)
SELECT * FROM "PatientEstimate" WHERE "_Recno" = 8928 -- (1)
SELECT * FROM "Phrase" WHERE "_Recno" = 9718 -- (1)
SELECT * FROM "Table" WHERE "_Recno" = 4 -- (1)
SELECT * FROM "BreedEntry" WHERE "_Recno" = 3283 -- (1)
O número após a consulta é o número de vezes que a consulta exata está sendo executada, por exemplo, a consulta SELECT * FROM "Patient" WHERE "_Recno" = 35051
está sendo executada 106 vezes, com esse _Recno . Na verdade, existem 1.031 consultas sendo executadas para criar este relatório (neste caso, varia) - as 23 ou mais acima são as consultas distintas .
Agora, cada consulta acima é executada muito, muito rápido, estamos falando de algumas dezenas de microssegundos em cada caso. Na verdade, se você somar todas as 1.031 consultas usadas para fazer este relatório, o tempo total usado para todas elas é de apenas 59.193 microssegundos, ou apenas 59 milissegundos.
Portanto, o problema e o atraso parecem ser a sobrecarga - embora haja apenas cerca de 59 ms de tempo real do banco de dados, o relatório leva cerca de 10 a 15 segundos para ser executado para o cliente, pois está indo e voltando com mais de 1.000 consultas.
Observe que, na maioria dos casos, o aplicativo cliente e o SQL Server estão na mesma máquina e várias instâncias do cliente são acessadas por meio do RDP. Em alguns casos, o cliente está em uma máquina diferente na LAN e imagino que o desempenho seria pior lá. Mas você pode considerar que, na maioria dos casos, não deve haver um problema de rede, pois o aplicativo cliente e o SQL Server estão na mesma caixa física.
Os dez segundos são até meio aceitáveis, o problema é que em horários mais movimentados isso pode aumentar para até um minuto ou mais.
Alguma ideia de como lidar com a otimização disso? Se fosse um aplicativo que eu tivesse acesso à fonte, obviamente substituiria tudo isso por uma ou algumas consultas que usavam junções, mas isso não é uma opção, o aplicativo é uma caixa preta - tudo o que posso fazer é otimizar do lado do SQL Server.
Falando com o cliente, embora o desempenho seja ruim, esteja ele usando o RDP ou a instalação de um aplicativo cliente remoto, o desempenho é muito pior com o aplicativo cliente remoto e isso é mais um problema para eles. Portanto, qualquer sugestão sobre coisas que eu possa observar para melhorar o desempenho lá, em relação à rede ou qualquer outra coisa, seria apreciada. Uma coisa a observar é que esta caixa do SQL 2014 agora está virtualizada, antes eles estavam usando, acho, 2008 ou 2012, mas não foi virtualizado - eles dizem que esse relatório era mais rápido naquela época. Eles têm outros motivos para querer que seja virtualizado; removê-lo da virtualização não é uma opção.
Ele se conecta usando a autenticação do Windows e (tenho certeza) TCP/IP. Acho que não conseguiria mudar isso. Não está caindo e restabelecendo as conexões, pelo menos, parece estar usando o pool de conexões.
Eu uso o Hibernate no meu trabalho diário e já me deparei com esse tipo de cenário antes, com o ORM gerando milhares de consultas, e minha solução usual é olhar para a estratégia de busca (carregamento preguiçoso vs carregamento ansioso) no código ou mesmo no caso de relatórios, geralmente reescreve tudo em SQL. Neste caso, embora o software seja o que é, um executável do Windows, e não há nada que eu possa fazer sobre isso, só posso abordar o lado SQL.
Meu entendimento é que o fornecedor não oferece mais suporte a esta versão específica e voltou para uma versão que usa arquivos simples em vez de SQL. Isso não funcionaria para o cliente - eles têm esse banco de dados integrado a várias outras coisas. É um software de nicho e, como muito desse tipo de software, é tecnicamente terrível no back-end, mas possui a funcionalidade de que o usuário do nicho precisa. De qualquer forma, não posso mudar o software, apenas o que se passa no SQL Server. Era inutilizável e eu o tornei utilizável, então fiz progressos trabalhando dentro dessas restrições.
Não há bloqueio ou bloqueio, verifiquei isso. Na verdade, esse foi o principal problema de desempenho que consertei, mas não houve nada bloqueando o tempo suficiente para ser registrado no último mês ou mais. A memória não é realmente um problema, pois o SQL Server Express é limitado a 1 GB de qualquer maneira. Ao olhar para ele, embora eu não ache que haja um problema de memória, disco, se houver, parece ser o maior ponto de estrangulamento de hardware.