Ralentissement des performances de SQL Server après l'allocation de davantage de CPU et de RAM


33

SQL Server 2008 R2 (10.50.1600) est exécuté sur un serveur virtuel Windows 2008 R2. Après la mise à niveau du processeur de 1 cœur à 4 ordinateurs et de la RAM de 4 Go à 10 Go, nous avons constaté une baisse des performances.

Quelques observations que je vois:

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

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

Par sp_BlitzErik, j'ai couru

EXEC dbo.sp_BlitzFirst @SinceStartup = 1;

En me donnant ces résultats.

attendre les statistiques


9
La dernière fois que j'ai vu une question similaire sur SE, c'était parce que quelqu'un avait retourné les processeurs et la RAM de la machine virtuelle, mais que l'hôte de la machine virtuelle n'avait pas réellement autant de processeurs et de mémoire vive . Donc, je vérifierais cela en premier.
user253751

Réponses:


55

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

  1. La version 2008R2 RTM est sortie le 21 avril 2010. Elle n’est plus supportée. Vous aurez pour priorité de vous procurer le dernier Service Pack, qui est sorti il ​​y a à peu près 3 ans aujourd'hui. De cette façon, vous serez couvert si vous rencontrez un bug étrange ou quelque chose. Rendez-vous ici pour savoir ce que vous devez télécharger.

  2. Comme vous avez ajouté des vCPU (de 1 à 4) et n'avez modifié aucun paramètre, vos requêtes peuvent maintenant être parallèles. Je sais que cela sonne comme si tout allait être plus rapide, mais accrochez-vous!

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

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

Vous voudrez utiliser sp_BlitzFirst pour consulter les statistiques d'attente de votre serveur. Vous pouvez l'exécuter de plusieurs 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é quelles demandes sont en attente (il y a une tonne d'articles sur les statistiques d'attente), vous pouvez commencer à apporter des modifications pour que tout soit sous contrôle.

Si vous les voyez attendre CXPACKET, cela signifie que vos requêtes vont en parallèle, et peut-être se piétinent. Si vous cliquez là-dessus, vous voudrez probablement envisager d’augmenter le seuil de coût pour le parallélisme jusqu’à 50, et peut-être de ramener MAXDOP à 2.

Après cette étape, vous souhaitez utiliser quelque chose comme sp_WhoIsActive ou sp_BlitzWho (ce dernier est déjà dans le référentiel GitHub) pour commencer à capturer les plans de requête. Mis à part les statistiques d'attente, il s'agit de l'une des choses les plus importantes à considérer pour comprendre ce qui ne va pas.

Vous pouvez également consulter cet article de Jonathan Kehayias sur les compteurs VMWare à 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 processeurs. Votre serveur est généralement ennuyé, mais quand les choses se réchauffent, les choses se détériorent. Je vais essayer de décomposer cela facilement.

  1. Vous frappez une attente empoisonnée appelée THREADPOOL. Vous n'en avez pas une tonne, mais c'est logique car votre serveur n'est pas très actif. Je vais expliquer pourquoi dans une minute.

  2. Vous avez des attentes moyennes très longues SOS_SCHEDULER_YIELDet CXPACKET. Vous êtes sur une machine virtuelle, vous devez donc vous assurer que SQL Server a des réservations ou que la boîte n'est pas terriblement sursouscrite. Un voisin bruyant peut vraiment gâcher votre journée ici. Vous allez également vouloir vous assurer que le serveur / l'invité VM / l'hôte VM ne s'exécutent pas en mode d'alimentation équilibrée. Cela permet à vos processeurs de ralentir inutilement, sans retour immédiat à la vitesse maximale.

  3. Comment sont-ils liés? Avec 4 processeurs, vous avez 512 threads de travail. N'oubliez pas 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? Très 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 poste de travail de ce type .

DES NOISETTES

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

Lorsque de nombreuses requêtes parallèles sont lancées, vous manquez de ces threads de travail. Lorsque cela se produit, les requêtes restent en attente des threads. C’est également là que les SOS_SCHEDULER_YIELDchoses entrent en jeu. Les requêtes quittent les processeurs et ne s’allument pas pendant longtemps. Je ne vois aucune attente bloquante, alors vous êtes probablement tous coincés dans les 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. Changer MAXDOP à 2
  3. Changer le seuil de coût pour le parallélisme à 50
  4. Suivez l'article de Jon K. ci-dessus pour valider la santé des ordinateurs virtuels.
  5. Utilisez le script appelé sp_BlitzIndexpour rechercher les demandes d'index manquantes.

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!



5

Une chose que je n'ai pas vue souligner est que l'ajout de vCPU à une machine virtuelle peut très souvent la ralentir en raison de la planification.

L'idée de base est que si une machine virtuelle a 4 vCPU, l'hyperviseur doit attendre que 4 cœurs physiques soient disponibles pour pouvoir planifier toutes les vCPU, même si 3 d'entre eux sont inactifs.

Si votre hôte ne contient pas beaucoup de cœurs 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 concret de ce qui se passe et comment cela a été diagnostiqué .

L'ajout de RAM supplémentaire peut également entraîner une baisse soudaine des performances si l'allocation de RAM de la machine virtuelle est supérieure à un nœud NUMA.

De plus, la configuration de vos vCPU (vSockets contre vCores) peut en réalité affecter certaines applications telles que SQL Server. Cela est dû au fait que le serveur SQL est lui-même conscient de NUMA (pour éviter le même type de perte de performances de NUMA-spanning) 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 également examiner et prendre en compte ces éléments.


3

Juste une petite aide (je ne peux pas poster ceci en tant que commentaire), en continuant la réponse de @ sp_BlitzErik, Pinal et Max Vernon (je ne me souviens plus où) utiliseraient des requêtes spécifiant la quantité maximale de MAXDOP à 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));

Le premier script renvoie un résultat vide. Le second retourne une suggestion MAXDOP = 2qui est juste en ligne avec @sp_BlitzErik. Merci!
Jeff le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.