Desempenho mais lento do SQL Server após alocar mais CPU e RAM


33

Temos o SQL Server 2008 R2 (10.50.1600) em execução em um servidor virtual Windows 2008 R2. Depois de atualizar a CPU de 1 núcleo para 4 e a RAM de 4 para 10 GB, notamos que o desempenho é pior.

Algumas observações que eu vejo:

  1. Uma consulta que levou <5 segundos para ser executada agora está levando> 200 segundos.
  2. A CPU é atribuída a 100 com sqlservr.exe como o culpado.
  3. Uma contagem de seleção (*) em uma tabela com 4,6 milhões de linhas levou mais de 90 segundos.
  4. Os processos em execução no servidor não foram alterados. A única mudança foi aumentar a CPU e o RAM.
  5. Outros servidores sql têm um arquivo de paginação estático no qual esse servidor está configurado para gerenciá-lo por conta própria.

Alguém já encontrou esse problema antes?

Por sp_BlitzErik, eu corri

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Dando-me esses resultados.

aguarde estatísticas


9
A última vez que vi uma pergunta semelhante no SE, foi porque alguém apareceu com as CPUs e a RAM da VM, mas o host da VM não tinha realmente tantas CPUs e tanta RAM . Então eu verificaria isso primeiro.
user253751

Respostas:


55

Há muita coisa acontecendo aqui, e a maioria é bastante ampla e vaga.

  1. O 2008R2 RTM saiu em 21 de abril de 2010. Está totalmente sem suporte. Você deve priorizar o acesso ao Service Pack mais recente, lançado há apenas três anos. Dessa forma, você estará coberto se estiver atingindo um bug estranho ou algo assim. Vá até aqui para descobrir o que você precisa baixar.

  2. Como você adicionou vCPUs (de 1 a 4) e não alterou nenhuma configuração, suas consultas agora podem ficar paralelas. Sei que parece que todos serão mais rápidos, mas espere!

  3. Você pode ter adicionado RAM, mas talvez não tenha alterado a Memória máxima do servidor para que o servidor possa tirar proveito dela.

  4. Descubra o que seu servidor está esperando. Um projeto de código aberto no qual trabalho fornece scripts gratuitos para ajudá-lo a medir seu SQL Server. Vá até aqui se você quiser experimentá-los.

Você vai querer pegar o sp_BlitzFirst para verificar as estatísticas de espera do seu servidor. Você pode executá-lo de duas maneiras.

Isso mostrará o que seu servidor está esperando desde que foi iniciado.

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Isso mostrará quais consultas estão aguardando agora, durante uma janela de 30 segundos.

EXEC dbo.sp_BlitzFirst @Seconds = 30, @ExpertMode = 1;

Depois de descobrir em que consultas estão aguardando (há muitas coisas escritas sobre estatísticas de espera por aí), você pode começar a fazer alterações para controlar as coisas.

Se você vê-los esperando CXPACKET , isso significa que suas consultas estão paralelas e talvez atropelando umas às outras. Se você acertar isso, provavelmente desejará aumentar o Limiar de custo para paralelismo até 50 e, talvez, reduzir o MAXDOP para 2.

Após esta etapa, é quando você deseja usar algo como sp_WhoIsActive ou sp_BlitzWho (o último está no repositório GitHub anterior) para começar a capturar planos de consulta. Além das estatísticas de espera, elas são uma das coisas mais importantes que você pode observar para descobrir o que está errado.

Você também pode conferir este artigo de Jonathan Kehayias sobre os contadores do VMWare para verificar em relação ao SQL Server.

Atualizar

Revendo as estatísticas de espera e menino, eles são estranhos. Definitivamente, há algo com as CPUs. Seu servidor geralmente fica entediado, mas quando as coisas esquentam, as coisas ficam ruins. Vou tentar quebrar isso facilmente.

  1. Você está atingindo uma espera de veneno chamada THREADPOOL. Você não tem muito disso, mas isso faz sentido porque seu servidor não está muito ativo. Vou explicar o porquê em um minuto.

  2. Você tem realmente longas esperas médias SOS_SCHEDULER_YIELDe CXPACKET. Você está em uma VM, portanto, certifique-se de que o SQL Server tenha reservas ou que a caixa não esteja terrivelmente em excesso. Um vizinho barulhento pode realmente arruinar o seu dia aqui. Você também precisará garantir que o servidor / convidado da VM / host da VM não esteja sendo executado no modo de energia balanceada. Isso faz com que suas CPUs diminuam desnecessariamente para velocidades baixas e não retornam imediatamente à velocidade máxima.

  3. Como eles se encaixam? Com 4 CPUs, você tem 512 threads de trabalho. Lembre-se de que você tinha a mesma quantidade com uma única CPU, mas agora que suas consultas podem ficar paralelas, elas podem consumir muito mais threads de trabalho. No seu caso, 4 threads por ramo paralelo de uma consulta paralela.

O que está acontecendo paralelo? Provavelmente tudo. O limiar de custo padrão para paralelismo é 5. Esse número foi feita a algum padrão no final dos anos 90 trabalhando em um desktop que olhou como esta .

NUTS

É verdade que seu hardware é menor que a maioria dos laptops, mas você ainda está um pouco à frente disso.

Quando muitas consultas paralelas acontecem, você está ficando sem esses segmentos de trabalho. Quando isso acontece, as consultas ficam paradas aguardando o andamento dos tópicos. Também é ondeSOS_SCHEDULER_YIELD entra. As consultas estão desativando as CPUs e não voltando a funcionar por um longo tempo. Como não vejo esperas de bloqueio, é provável que você tenha apenas esperas paralelas dentro da consulta.

O que você pode fazer?

  1. Verifique se nada está no modo de energia balanceada
  2. Altere MAXDOP para 2
  3. Alterar o limite de custo do paralelismo para 50
  4. Siga o artigo de Jon K. acima para validar a integridade da VM
  5. Use o script chamado sp_BlitzIndexpara procurar por quaisquer pedidos de índice ausentes.

Para uma solução de problemas mais completa, consulte o whitepaper que escrevi para o Google sobre dimensionamento de hardware na nuvem.

Espero que isto ajude!



5

Uma coisa que não vi apontada é que a adição de vCPUs a uma VM muitas vezes pode desacelerá-la devido ao agendamento.

A idéia básica é que, se uma VM tiver 4 vCPUs, o hipervisor deverá aguardar a disponibilidade de 4 núcleos físicos para que possa agendar todas as vCPUs, mesmo que três delas estejam ociosas.

Se você não possui muitos núcleos no host e outras cargas de trabalho estão ocupadas, isso pode resultar em espera extra e uma queda significativa no desempenho.

No VMware ESXi, você pode vê-lo nos gráficos avançados via CPU Ready.

Aqui está um dos muitos artigos com um exemplo real do ocorrido e como ele foi diagnosticado .

Adicionar mais RAM também pode causar uma queda súbita no desempenho se a alocação de RAM da VM for maior que um nó NUMA.

Além disso, a configuração de suas vCPUs (vSockets vs. vCores) pode realmente afetar alguns aplicativos como o SQL Server. Isso ocorre porque o próprio servidor SQL reconhece NUMA (para evitar o mesmo tipo de queda de desempenho que abrange NUMA) e porque o VMware pode apresentar nós NUMA virtuais de maneira diferente.

Isso é abordado em uma postagem no blog do site da VMware .


Dito isto, estou feliz que você tenha resolvido os problemas com a ajuda de Erik, mas você pode querer examinar e considerar essas coisas também.


3

Apenas uma pequena ajuda (não é possível postar isso como um comentário) continuando a resposta de @ sp_BlitzErik, recebi algumas consultas com Pinal e Max Vernon (não posso lembrar onde) que dizem quanto MAXDOP você deve usar:

/*************************************************************************
Author          :   Kin Shah
Purpose         :   Recommend MaxDop settings for the server instance
Tested RDBMS    :   SQL Server 2008R2

**************************************************************************/
declare @hyperthreadingRatio bit
declare @logicalCPUs int
declare @HTEnabled int
declare @physicalCPU int
declare @SOCKET int
declare @logicalCPUPerNuma int
declare @NoOfNUMA int

select @logicalCPUs = cpu_count -- [Logical CPU Count]
    ,@hyperthreadingRatio = hyperthread_ratio --  [Hyperthread Ratio]
    ,@physicalCPU = cpu_count / hyperthread_ratio -- [Physical CPU Count]
    ,@HTEnabled = case 
        when cpu_count > hyperthread_ratio
            then 1
        else 0
        end -- HTEnabled
from sys.dm_os_sys_info
option (recompile);

select @logicalCPUPerNuma = COUNT(parent_node_id) -- [NumberOfLogicalProcessorsPerNuma]
from sys.dm_os_schedulers
where [status] = 'VISIBLE ONLINE'
    and parent_node_id < 64
group by parent_node_id
option (recompile);

select @NoOfNUMA = count(distinct parent_node_id)
from sys.dm_os_schedulers -- find NO OF NUMA Nodes 
where [status] = 'VISIBLE ONLINE'
    and parent_node_id < 64

-- Report the recommendations ....
select
    --- 8 or less processors and NO HT enabled
    case 
        when @logicalCPUs < 8
            and @HTEnabled = 0
            then 'MAXDOP setting should be : ' + CAST(@logicalCPUs as varchar(3))
                --- 8 or more processors and NO HT enabled
        when @logicalCPUs >= 8
            and @HTEnabled = 0
            then 'MAXDOP setting should be : 8'
                --- 8 or more processors and HT enabled and NO NUMA
        when @logicalCPUs >= 8
            and @HTEnabled = 1
            and @NoofNUMA = 1
            then 'MaxDop setting should be : ' + CAST(@logicalCPUPerNuma / @physicalCPU as varchar(3))
                --- 8 or more processors and HT enabled and NUMA
        when @logicalCPUs >= 8
            and @HTEnabled = 1
            and @NoofNUMA > 1
            then 'MaxDop setting should be : ' + CAST(@logicalCPUPerNuma / @physicalCPU as varchar(3))
        else ''
        end as Recommendations

-------------------------------------------------- -------

--MAX VERNON 

/* 
   This will recommend a MAXDOP setting appropriate for your machine's NUMA memory
   configuration.  You will need to evaluate this setting in a non-production 
   environment before moving it to production.

   MAXDOP can be configured using:  
   EXEC sp_configure 'max degree of parallelism',X;
   RECONFIGURE

   If this instance is hosting a Sharepoint database, you MUST specify MAXDOP=1 
   (URL wrapped for readability)
   http://blogs.msdn.com/b/rcormier/archive/2012/10/25/
   you-shall-configure-your-maxdop-when-using-sharepoint-2013.aspx

   Biztalk (all versions, including 2010): 
   MAXDOP = 1 is only required on the BizTalk Message Box
   database server(s), and must not be changed; all other servers hosting other 
   BizTalk Server databases may return this value to 0 if set.
   http://support.microsoft.com/kb/899000
*/
SET NOCOUNT ON;

DECLARE @CoreCount int;
SET @CoreCount = 0;
DECLARE @NumaNodes int;

/*  see if xp_cmdshell is enabled, so we can try to use 
    PowerShell to determine the real core count
*/
DECLARE @T TABLE (
    name varchar(255)
    , minimum int
    , maximum int
    , config_value int
    , run_value int
);
INSERT INTO @T 
EXEC sp_configure 'xp_cmdshell';
DECLARE @cmdshellEnabled BIT;
SET @cmdshellEnabled = 0;
SELECT @cmdshellEnabled = 1 
FROM @T
WHERE run_value = 1;
IF @cmdshellEnabled = 1
BEGIN
    CREATE TABLE #cmdshell
    (
        txt VARCHAR(255)
    );
    INSERT INTO #cmdshell (txt)
    EXEC xp_cmdshell 'powershell -OutputFormat Text -NoLogo -Command "& {Get-WmiObject -namespace "root\CIMV2" -class Win32_Processor -Property NumberOfCores} | select NumberOfCores"';
    SELECT @CoreCount = CONVERT(INT, LTRIM(RTRIM(txt)))
    FROM #cmdshell
    WHERE ISNUMERIC(LTRIM(RTRIM(txt)))=1;
    DROP TABLE #cmdshell;
END
IF @CoreCount = 0 
BEGIN
    /* 
        Could not use PowerShell to get the corecount, use SQL Server's 
        unreliable number.  For machines with hyperthreading enabled
        this number is (typically) twice the physical core count.
    */
    SET @CoreCount = (SELECT i.cpu_count from sys.dm_os_sys_info i); 
END

SET @NumaNodes = (
    SELECT MAX(c.memory_node_id) + 1 
    FROM sys.dm_os_memory_clerks c 
    WHERE memory_node_id < 64
    );

DECLARE @MaxDOP int;

/* 3/4 of Total Cores in Machine */
SET @MaxDOP = @CoreCount * 0.75; 

/* if @MaxDOP is greater than the per NUMA node
    Core Count, set @MaxDOP = per NUMA node core count
*/
IF @MaxDOP > (@CoreCount / @NumaNodes) 
    SET @MaxDOP = (@CoreCount / @NumaNodes) * 0.75;

/*
    Reduce @MaxDOP to an even number 
*/
SET @MaxDOP = @MaxDOP - (@MaxDOP % 2);

/* Cap MAXDOP at 8, according to Microsoft */
IF @MaxDOP > 8 SET @MaxDOP = 8;

PRINT 'Suggested MAXDOP = ' + CAST(@MaxDOP as varchar(max));

O primeiro script retorna um resultado em branco. O segundo retorna uma sugestão MAXDOP = 2que está alinhada com @sp_BlitzErik. Obrigado!
Jeff Jeff
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.