Rendimiento más lento de SQL Server después de asignar más CPU y RAM

33

Tenemos SQL Server 2008 R2 (10.50.1600) ejecutándose en un servidor virtual de Windows 2008 R2. Después de actualizar la CPU de 1 núcleo a 4 y la RAM de 4 gb a 10 gb, hemos notado que el rendimiento es peor.

Algunas observaciones que veo:

  1. Una consulta que tardó <5 segundos en ejecutarse ahora tarda> 200 segundos.
  2. La CPU está vinculada a 100 con sqlservr.exe como el culpable.
  3. Un recuento de selección (*) en una tabla con 4.6 millones de filas tomó más de 90 segundos.
  4. Los procesos que se ejecutan en el servidor no han cambiado. El único cambio fue aumentar la CPU y el RAM.
  5. Otros servidores sql tienen un archivo de paginación estático donde este servidor está configurado para administrarlo por sí mismo.

¿Alguien se ha encontrado con este problema antes?

Por sp_BlitzErik, corrí

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Dándome estos resultados.

estadísticas de espera

Jeff
fuente
99
La última vez que vi una pregunta similar sobre SE, fue porque alguien encendió las CPU y RAM de la VM, pero el host de la VM en realidad no tenía tantas CPU y tanta RAM . Así que comprobaría eso primero.
user253751

Respuestas:

55

Están sucediendo muchas cosas aquí, y la mayoría es bastante amplia y vaga.

  1. 2008R2 RTM salió el 21 de abril de 2010. Está totalmente fuera de soporte. Querrás priorizar el obtener el último Service Pack, que salió hace solo 3 años. De esa manera, estarás cubierto si te encuentras con un error extraño o algo así. Dirígete aquí para descubrir qué necesitas descargar.

  2. Como agregó vCPU (de 1 a 4) y no cambió ninguna configuración, sus consultas ahora pueden ir en paralelo. Sé que parece que todos serán más rápidos, ¡pero espera!

  3. Es posible que haya agregado RAM, pero es posible que no haya cambiado la memoria máxima del servidor para que su servidor pueda aprovecharla.

  4. Averigua qué está esperando tu servidor. Un proyecto de código abierto en el que trabajo proporciona scripts gratuitos para ayudarlo a medir su SQL Server. Pásate por aquí si quieres intentarlo.

Querrás obtener sp_BlitzFirst para ver las estadísticas de espera de tu servidor. Puedes ejecutarlo de dos maneras.

Esto le mostrará lo que su servidor ha estado esperando desde que se inició.

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Esto le mostrará qué consultas están esperando ahora, durante una ventana de 30 segundos.

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

Una vez que descubra qué consultas están esperando (hay un montón de cosas escritas sobre las estadísticas de espera), puede comenzar a hacer cambios para tener las cosas bajo control.

Si los ve esperando CXPACKET, eso significa que sus consultas van paralelas y tal vez se pisotean entre sí. Si logra esto, probablemente desee considerar aumentar el Umbral de costo para paralelismo hasta 50, y tal vez bajar MAXDOP a 2.

Después de este paso es cuando desea usar algo como sp_WhoIsActive o sp_BlitzWho (este último se encuentra en el repositorio de GitHub de antes) para comenzar a capturar planes de consulta. Además de las estadísticas de espera, son una de las cosas más importantes que puedes ver para descubrir qué está mal.

También puede consultar este artículo de Jonathan Kehayias sobre VMWare Counters para consultar en relación con SQL Server.

Actualizar

Revisando las estadísticas de espera y chico, son raros Definitivamente hay algo con las CPU. Su servidor está más que nada aburrido, pero cuando las cosas se calientan, las cosas se ponen mal. Intentaré analizar esto fácilmente.

  1. Estás golpeando una llamada de veneno llamada THREADPOOL. No tiene una tonelada, pero eso tiene sentido porque su servidor no está terriblemente activo. Explicaré por qué en un minuto.

  2. Tienes un promedio de espera muy largo SOS_SCHEDULER_YIELDy CXPACKET. Estás en una máquina virtual, por lo que querrás asegurarte de que el servidor SQL tenga reservas o que la caja no esté demasiado suscrita. Un vecino ruidoso realmente puede arruinar tu día aquí. También querrá asegurarse de que el servidor / invitado de VM / host de VM no se esté ejecutando en modo de energía equilibrada. Esto hace que sus CPU bajen a velocidades innecesariamente bajas, y no vuelven inmediatamente a la velocidad máxima.

  3. ¿Cómo se unen? Con 4 CPU tiene 512 hilos de trabajo. Tenga en cuenta que tenía la misma cantidad con una sola CPU, pero ahora que sus consultas pueden ir en paralelo, pueden consumir muchos más subprocesos de trabajo. En su caso, 4 hilos por rama paralela de una consulta paralela.

¿Qué va paralelo? Lo más probable es que todo. El umbral de costo predeterminado para el paralelismo es 5. Ese número se convirtió en el predeterminado en algún momento a fines de los años 90 trabajando en un escritorio que se parecía a esto .

NUECES

De acuerdo, su hardware es más pequeño que la mayoría de las computadoras portátiles, pero todavía está un poco por delante de eso.

Cuando se inician muchas consultas paralelas, se está quedando sin esos subprocesos de trabajo. Cuando eso sucede, las consultas simplemente se quedan esperando que los hilos se pongan en marcha. Ahí también es donde SOS_SCHEDULER_YIELDentra. Las consultas están saliendo de las CPU y no vuelven a funcionar durante mucho tiempo. No veo ninguna espera de bloqueo, por lo que lo más probable es que esté lleno de esperas de paralelismo intraconsulta.

¿Qué puedes hacer?

  1. Asegúrese de que nada esté en modo de energía equilibrada
  2. Cambiar MAXDOP a 2
  3. Cambiar el umbral de costo para paralelismo a 50
  4. Siga el artículo anterior de Jon K. para validar el estado de VM
  5. Use el script llamado sp_BlitzIndexpara buscar cualquier solicitud de índice faltante.

Para una resolución de problemas más exhaustiva, consulte el documento técnico que escribí para Google sobre el tamaño del hardware en la nube.

¡Espero que esto ayude!

Erik Darling
fuente
8

¡Sí! He experimentado este tipo de situación en SQL Server vms en nuestra granja de servidores. Mire el tiempo de preparación de la CPU del host vm y los contadores del controlador del globo de memoria. TIEMPO LISTO PARA LA CPU: BLOG PARTE I y comprensión de VMware Ballooning Trabajar con mi administrador de sistemas fue clave, pero no fue fácil ...

thundercougarfalcon
fuente
5

Una cosa que no vi señalada es que agregar vCPU a una VM a menudo puede ralentizarla debido a la programación.

La idea básica es que si una VM tiene 4 vCPU, entonces el hipervisor debe esperar a que estén disponibles 4 núcleos físicos para poder programar todas las vCPU, incluso si 3 de ellas están inactivas.

Si no tiene muchos núcleos en su host y sus otras cargas de trabajo están ocupadas, esto puede resultar en una espera adicional y una caída significativa en el rendimiento.

En VMware ESXi puede verlo en los gráficos avanzados a través de CPU Ready.

Aquí hay uno de los muchos artículos con un ejemplo del mundo real de cómo sucedió esto y cómo se diagnosticó .

Agregar más RAM también puede causar una caída repentina del rendimiento si la asignación de RAM de la VM es mayor que un nodo NUMA.

Además, la configuración de sus vCPU (vSockets vs. vCores) puede afectar algunas aplicaciones como el servidor SQL. Esto se debe a que el servidor SQL es consciente de NUMA (para evitar el mismo tipo de caída de rendimiento que abarca NUMA) y porque VMware puede presentar nodos NUMA virtuales de manera diferente.

Esto está cubierto en una publicación de blog en el propio sitio de VMware .


Dicho esto, me alegro de que haya resuelto los problemas con la ayuda de Erik, pero es posible que también desee considerar y considerar estas cosas.

briantista
fuente
3

Solo un poco de ayuda (no puedo publicar esto como un comentario) continuando la respuesta de @ sp_BlitzErik, recibí algunas consultas con Pinal y Max Vernon (no recuerdo dónde) que dicen cuánto MAXDOP debe 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));
Racer SQL
fuente
El primer script devuelve un resultado en blanco. El segundo devuelve una sugerencia MAXDOP = 2que está en línea con @sp_BlitzErik. ¡Gracias!
Jeff