web-dev-qa-db-fra.com

Ralentissement des performances de SQL Server après avoir alloué plus de CPU et RAM

Nous avons SQL Server 2008 R2 (10.50.1600) en cours d'exécution sur un serveur virtuel Windows 2008 R2. Après avoir mis à niveau le processeur de 1 cœur à 4 et le RAM de 4 Go à 10 Go, nous avons remarqué que les performances étaient pires.

Quelques observations que je vois:

  1. Une requête qui a pris <5 secondes pour s'exécuter prend maintenant> 200 secondes.
  2. Le processeur est fixé à 100 avec sqlservr.exe comme coupable.
  3. Un décompte sélectionné (*) sur une table avec 4,6 millions de lignes a pris plus de 90 secondes.
  4. Les processus en cours d'exécution sur le serveur n'ont pas changé. Le seul changement a consisté à augmenter le CPU et le RAM.
  5. D'autres serveurs SQL ont un fichier de pagination statique dans lequel ce serveur est configuré pour le gérer seul.

Quelqu'un a-t-il déjà rencontré ce problème?

Par sp_BlitzErik, j'ai couru

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Me donnant ces résultats.

wait stats

33
Jeff

Il se passe beaucoup de choses ici, et la plupart sont assez larges et vagues.

  1. 2008R2 RTM est sorti le 21 avril 2010. Il est totalement hors support. Vous voudrez donner la priorité à la mise à jour du dernier Service Pack, qui est sorti il ​​y a environ 3 ans jour pour jour. De cette façon, vous serez couvert si vous rencontrez un bug bizarre ou quelque chose comme ça. Allez sur ici pour comprendre ce que vous devez télécharger.

  2. Puisque vous avez ajouté des vCPU (de 1 à 4) et n'avez modifié aucun paramètre, vos requêtes peuvent désormais être parallèles. Je sais que cela semble être plus rapide, mais attendez!

  3. Vous avez peut-être ajouté de la RAM, mais vous n'avez peut-être pas modifié la mémoire maximale du serveur afin que votre serveur puisse en profiter.

  4. Découvrez ce que votre serveur attend. Un projet open source sur lequel je travaille fournit des scripts gratuits pour vous aider à mesurer votre SQL Server. Allez ici si vous voulez essayer.

Vous voudrez saisir sp_BlitzFirst pour consulter les statistiques d'attente de votre serveur. Vous pouvez l'exécuter de deux manières.

Cela vous montrera ce que votre serveur attend depuis son démarrage.

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

Cela vous montrera quelles requêtes attendent maintenant, pendant une fenêtre de 30 secondes.

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

Une fois que vous avez déterminé les requêtes en attente (il y a une tonne de choses écrites sur les statistiques d'attente), vous pouvez commencer à apporter des modifications pour contrôler les choses.

Si vous les voyez attendre sur CXPACKET, cela signifie que vos requêtes vont en parallèle, et peut-être se piétinent. Si vous touchez cela, vous voudrez probablement envisager de faire passer le seuil de coût pour le parallélisme à 50, et peut-être de réduire MAXDOP à 2.

Après cette étape, vous devez utiliser quelque chose comme sp_WhoIsActive ou sp_BlitzWho (ce dernier se trouve dans le référentiel GitHub précédent) pour commencer à capturer les plans de requête. Mis à part les statistiques d'attente, elles sont l'une des choses les plus importantes que vous pouvez regarder pour comprendre ce qui ne va pas.

Vous pouvez également consulter cet article de Jonathan Kehayias sur VMWare Counters à consulter en relation avec SQL Server.

Mise à jour

Revoir les statistiques d'attente et le garçon sont-ils étranges. Il y a définitivement quelque chose avec les CPU. Votre serveur est généralement ennuyé, mais lorsque les choses chauffent, les choses vont mal. J'essaierai de décomposer cela facilement.

  1. Vous frappez un poison wait appelé THREADPOOL. Vous n'en avez pas une tonne, mais cela a du sens car votre serveur n'est pas terriblement actif. Je vais vous expliquer pourquoi dans une minute.

  2. Vous avez en moyenne de très longues attentes sur SOS_SCHEDULER_YIELD et CXPACKET. Vous êtes sur une machine virtuelle, vous voudrez donc vous assurer que le serveur SQL a des réservations ou que la boîte n'est pas horriblement sursouscrite. Un voisin bruyant peut vraiment gâcher votre journée ici. Vous voudrez également vous assurer que le serveur/l'invité VM/l'hôte VM ne s'exécute pas en mode d'alimentation équilibrée. Cela fait que vos processeurs tournent à des vitesses inutilement basses, et ils ne reviennent pas immédiatement à pleine vitesse.

  3. Comment se lient-ils? Avec 4 CPU, vous disposez de 512 threads de travail. Gardez à l'esprit que vous aviez le même montant avec un seul processeur, mais maintenant que vos requêtes peuvent aller en parallèle, elles peuvent consommer beaucoup plus de threads de travail. Dans votre cas, 4 threads par branche parallèle d'une requête parallèle.

Qu'est-ce qui se passe en parallèle? Probablement tout. Le seuil de coût par défaut pour le parallélisme est 5. Ce nombre a été défini par défaut à la fin des années 90 sur un bureau qui ressemblait à comme ceci .

NUTS

Certes, votre matériel est plus petit que la plupart des ordinateurs portables, mais vous êtes toujours un peu en avance sur cette chose.

Lorsque de nombreuses requêtes parallèles sont lancées, vous êtes à court de ces threads de travail. Lorsque cela se produit, les requêtes attendent simplement que les threads démarrent. C'est aussi là que SOS_SCHEDULER_YIELD entre en jeu. Les requêtes quittent les processeurs et ne reprennent pas longtemps. Je ne vois aucune attente de blocage, vous êtes donc probablement tout bourré d'attentes de parallélisme intra-requête.

Que pouvez-vous faire?

  1. Assurez-vous que rien n'est en mode d'alimentation équilibrée
  2. Remplacez MAXDOP par 2
  3. Changer le seuil de coût pour le parallélisme à 50
  4. Suivez l'article de Jon K. ci-dessus pour valider VM health
  5. Utilisez le script appelé sp_BlitzIndex pour rechercher toute demande d'index manquante.

Pour un dépannage plus approfondi, consultez le livre blanc que j'ai écrit pour Google sur le dimensionnement du matériel dans le cloud.

J'espère que cela t'aides!

55
Erik Darling

Oui! J'ai rencontré ce type de situation sur SQL Server vms dans notre batterie de serveurs. Examinez le temps de préparation du processeur hôte du VM et les compteurs de pilote de ballon de mémoire. CPU READY TIME - BLOG PART I and nderstanding VMware Ballooning Travailler avec mon administrateur système était la clé, mais ce n'était pas facile ...

8
thundercougarfalcon

Une chose que je n'ai pas remarquée, c'est que l'ajout de vCPU à un VM peut très souvent le ralentir en raison de la planification.

L'idée de base est que si un VM possède 4 vCPU, l'hyperviseur doit attendre que 4 cœurs physiques soient disponibles pour pouvoir planifier tous les vCPU, même si 3 d'entre eux sont inactifs .

Si vous n'avez pas beaucoup de cœurs dans votre hôte et que vos autres charges de travail sont occupées, cela peut entraîner une attente supplémentaire et une baisse significative des performances.

Dans VMware ESXi, vous pouvez le voir dans les graphiques avancés via CPU Ready.

Voici l'un des nombreux articles avec un exemple réel de ce qui se passe et comment il a été diagnostiqué .

Ajouter plus RAM peut également entraîner une baisse soudaine des performances si l'allocation de la machine virtuelle RAM est plus grande qu'un nœud NUMA).

De plus, la configuration de vos vCPU (vSockets vs vCores) peut réellement affecter certaines applications comme le serveur SQL. Cela est dû au fait que le serveur SQL est lui-même compatible avec NUMA (pour éviter le même type de baisse des performances couvrant NUMA) et parce que VMware peut présenter les nœuds NUMA virtuels différemment.

Ceci est couvert dans un article de blog sur le propre site de VMware .


Cela étant dit, je suis heureux que vous ayez résolu les problèmes avec l'aide d'Erik, mais vous voudrez peut-être aussi examiner et considérer ces choses.

5
briantist

Juste un peu d'aide (je ne peux pas poster ceci en tant que commentaire) en poursuivant la réponse de @ sp_BlitzErik, j'ai reçu quelques requêtes avec Pinal et Max Vernon (je ne me souviens plus où) qui disent combien de MAXDOP vous devez utiliser:

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