Prestazioni più lente di SQL Server dopo aver allocato più CPU e RAM


33

SQL Server 2008 R2 (10.50.1600) è in esecuzione su un server Windows 2008 R2 virtuale. Dopo aver aggiornato la CPU da 1 core a 4 e la RAM da 4 GB a 10 GB, abbiamo notato che le prestazioni sono peggiori.

Alcune osservazioni che vedo:

  1. Una query che ha richiesto <5 secondi per essere eseguita ora impiega> 200 secondi.
  2. La CPU è bloccata a 100 con sqlservr.exe come colpevole.
  3. Un conteggio selezionato (*) su una tabella con 4,6 milioni di righe ha richiesto oltre 90 secondi.
  4. I processi in esecuzione sul server non sono cambiati. L'unica modifica è stata quella di aumentare la CPU e la RAM.
  5. Altri server sql hanno un file di paging statico in cui questo server è impostato per gestirlo da solo.

Qualcuno ha riscontrato questo problema prima?

Per sp_BlitzErik, ho corso

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Mi dà questi risultati.

aspetta statistiche


9
L'ultima volta che ho visto una domanda simile su SE, è stato perché qualcuno ha acceso le CPU e la RAM della VM, ma l'host di macchine virtuali in realtà non aveva così tante CPU e così tanta RAM . Quindi lo controllerei per primo.
user253751

Risposte:


55

C'è molto da fare qui, e la maggior parte è piuttosto ampia e vaga.

  1. 2008R2 RTM è uscito il 21 aprile 2010. È totalmente fuori supporto. Ti consigliamo di dare la priorità all'acquisto dell'ultimo Service Pack, uscito circa 3 anni fa. In questo modo sarai coperto se colpisci un bug strano o qualcosa del genere. Vai qui per capire cosa devi scaricare.

  2. Poiché hai aggiunto vCPU (da 1 a 4) e non hai modificato alcuna impostazione, le tue query possono ora andare in parallelo. So che sembra che saranno tutti più veloci, ma aspetta!

  3. Potresti aver aggiunto RAM, ma potresti non aver modificato Max Server Memory in modo che il tuo server possa trarne vantaggio.

  4. Scopri cosa sta aspettando il tuo server. Un progetto open source su cui lavoro fornisce script gratuiti per aiutarti a misurare il tuo SQL Server. Vai qui se vuoi provarli.

Ti consigliamo di prendere sp_BlitzFirst per controllare le statistiche di attesa del tuo server. Puoi eseguirlo in un paio di modi.

Questo ti mostrerà ciò che il tuo server ha atteso da quando è stato avviato.

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Questo ti mostrerà quali query sono in attesa ora, durante una finestra di 30 secondi.

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

Una volta che hai capito quali domande ti stanno aspettando (ci sono un sacco di cose scritte sulle statistiche di attesa là fuori), puoi iniziare a fare cambiamenti per tenere tutto sotto controllo.

Se li vedi in attesa CXPACKET, ciò significa che le tue query stanno andando in parallelo e forse calpestando l'una sull'altra. Se colpisci questo, probabilmente vorrai considerare di aumentare la Soglia di costo per il parallelismo fino a 50 e forse di far scendere MAXDOP fino a 2.

Dopo questo passaggio è quando si desidera utilizzare qualcosa come sp_WhoIsActive o sp_BlitzWho (quest'ultimo si trova nel repository GitHub da prima) per avviare l'acquisizione dei piani di query. A parte le statistiche sull'attesa, sono una delle cose più importanti che puoi guardare per capire cosa non va.

Puoi anche consultare questo articolo di Jonathan Kehayias sui contatori VMWare da verificare in relazione a SQL Server.

Aggiornare

Revisionare le statistiche di attesa e ragazzo sono strani. C'è sicuramente qualcosa che non va nelle CPU. Il tuo server è per lo più annoiato, ma quando le cose si surriscaldano, le cose peggiorano. Proverò a scomporlo facilmente.

  1. Stai colpendo un'attesa di veleno chiamata THREADPOOL. Non ne hai molto, ma ha senso perché il tuo server non è terribilmente attivo. Spiegherò perché tra un minuto.

  2. Hai attese medie molto lunghe su SOS_SCHEDULER_YIELDe CXPACKET. Sei su una macchina virtuale, quindi assicurati che SQL Server abbia delle prenotazioni o che la casella non sia eccessivamente sottoscritta. Un vicino rumoroso può davvero rovinare la tua giornata qui. Inoltre, vorrai assicurarti che il server / guest VM / host VM non siano in esecuzione in modalità di alimentazione bilanciata. Questo fa girare le CPU a velocità inutilmente basse e non tornano immediatamente alla massima velocità.

  3. Come si legano? Con 4 CPU hai 512 thread di lavoro. Tieni presente che hai avuto lo stesso importo con una singola CPU, ma ora che le tue query possono andare in parallelo, possono consumare molti più thread di lavoro. Nel tuo caso 4 thread per ramo parallelo di una query parallela.

Cosa sta andando parallelo? Molto probabilmente tutto. La soglia di costo predefinita per il parallelismo è 5. Quel numero è stato impostato come predefinito alla fine degli anni '90 lavorando su un desktop che assomigliava a questo .

NOCCIOLINE

Certo, il tuo hardware è più piccolo della maggior parte dei laptop, ma sei ancora un po 'avanti rispetto a quello.

Quando vengono avviate molte query parallele, si stanno esaurendo i thread di lavoro. Quando ciò accade, le query rimangono semplicemente in attesa che i thread inizino. È anche qui che SOS_SCHEDULER_YIELDentra in gioco. Le query stanno interrompendo le CPU e non si riaccendono per molto tempo. Non vedo alcuna attesa di blocco, quindi è molto probabile che tu sia solo pieno di attese di parallelismo intra-query.

Cosa sai fare?

  1. Assicurarsi che nulla sia in modalità di alimentazione bilanciata
  2. Cambia MAXDOP in 2
  3. Modifica la soglia di costo per il parallelismo su 50
  4. Segui l'articolo di Jon K. sopra per convalidare l'integrità della VM
  5. Utilizzare lo script chiamato sp_BlitzIndexper cercare eventuali richieste di indice mancanti.

Per una risoluzione dei problemi più approfondita, consulta il white paper che ho scritto per Google sul dimensionamento dell'hardware nel cloud.

Spero che sia di aiuto!



5

Una cosa che non ho visto sottolineato è che l'aggiunta di vCPU a una macchina virtuale può molto spesso rallentarla a causa della pianificazione.

L'idea di base è che se una VM ha 4 vCPU, l'hypervisor deve attendere la disponibilità di 4 core fisici in modo da poter pianificare tutte le vCPU, anche se 3 di esse sono inattive.

Se non disponi di molti core nel tuo host e i tuoi altri carichi di lavoro sono occupati, ciò può comportare ulteriori attese e un calo significativo delle prestazioni.

In VMware ESXi puoi vederlo nei grafici avanzati tramite CPU Ready.

Ecco uno dei tanti articoli con un esempio reale di ciò che sta accadendo e di come è stato diagnosticato .

L'aggiunta di più RAM può anche causare un improvviso calo delle prestazioni se l'allocazione RAM della VM è maggiore di un nodo NUMA.

Inoltre, la configurazione dei tuoi vCPU (vSocket vs. vCores) può effettivamente influenzare alcune applicazioni come SQL Server. Questo perché SQL Server è a sua volta a conoscenza di NUMA (per evitare lo stesso tipo di calo delle prestazioni di NUMA-spanning) e perché VMware può presentare nodi NUMA virtuali in modo diverso.

Questo è trattato in un post sul blog sul sito di VMware .


Detto questo, sono felice che tu abbia risolto i problemi con l'aiuto di Erik, ma potresti voler esaminare e considerare anche queste cose.


3

Solo un piccolo aiuto (non posso pubblicare questo come commento) continuando la risposta di @ sp_BlitzErik, ho ricevuto alcune domande con Pinal e Max Vernon (non ricordo dove) che dicono quanto MAXDOP dovresti usare:

/*************************************************************************
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));

Il primo script restituisce un risultato vuoto. Il secondo restituisce un suggerito MAXDOP = 2che è perfettamente in linea con @sp_BlitzErik. Grazie!
Jeff,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.