Was ist eine deterministische Methode zur Bewertung einer sinnvollen Pufferpoolgröße?


29

Ich versuche, einen vernünftigen Weg zu finden, um zu verstehen, ob die max server memory (mb)Einstellung angemessen ist (entweder sollte sie niedriger oder höher sein oder so bleiben, wie sie ist). Mir ist bewusst, dass max server memory (mb)immer niedrig genug sein sollte, um Platz für das Betriebssystem selbst usw. zu lassen.

Die Umgebung, die ich betrachte, hat mehrere hundert Server; Ich benötige eine verlässliche Formel, mit der ich feststellen kann, ob die aktuelle Größe des Pufferpools angemessen ist, da der Arbeitsspeicher pro GB berechnet wird, das jedem Server zugewiesen ist. Die gesamte Umgebung ist virtualisiert, und der einer VM zugewiesene "physische" RAM kann problemlos nach oben oder unten geändert werden.

Ich habe eine bestimmte SQL Server-Instanz, die ich gerade mit einem PLE von 1.100.052 Sekunden betrachte, was 12,7 Tagen entspricht (die Zeitdauer, die der Server aktiv war). Der Server hat eine maximale Serverspeichereinstellung von 2560 MB (2,5 GB), von denen nur 1380 MB (1,3 GB) tatsächlich festgeschrieben sind.

Ich habe mehrere Artikel gelesen, darunter einen von Jonathan Keheyias ( Beitrag ) und einen von Paul Randal ( Beitrag ) sowie mehrere andere. Jonathan befürwortet die Überwachung eines PLE unter 300 pro 4 GB Pufferpool als zu niedrig. Für die obige SQL Server-Instanz 300 * (2.5 / 4) = 187ergibt sich ein wirklich sehr niedriger Ziel-PLE-Wert unter 300. Diese Instanz verfügt über 290 GB SQL Server-Daten (ohne Protokolldateien) und wird nur für Integrationstests verwendet. Die letzten 12 Tage Unter der Annahme , ist repräsentativ für typische Verwendung für diesen Server, würde ich sagen , dass die max server memory (mb)Einstellung könnte gesenkt werden.

Am anderen Ende der Skala habe ich einen weiteren Integrationstestserver mit einem PLE von 294, der eine max server memory (mb)Einstellung von nur 1 GB hat. Dieser Server verfügt nur über 224 MB SQL Server-Daten ohne Protokolle und führt einige BizFlow-Datenbanken aus. Dieser Server kann von einer höheren max server memory (mb)Einstellung profitieren .

Ich denke, ein guter Ausgangspunkt für Ziele, denen möglicherweise zu viel Speicher zugewiesen wurde, könnte Folgendes sein:

SELECT 
    RamMB = physical_memory_in_bytes / 1048576
    , BufferPoolCommittedMB = bpool_committed * 8192E0 / 1048576
    , BufferPoolCommitTargetMB = bpool_commit_target * 8192E0 / 1048576
    , PercentOfDesiredSizeMB = CONVERT(INT,(CONVERT(DECIMAL(18,2),bpool_committed) 
                            / bpool_commit_target) * 100)
FROM sys.dm_os_sys_info;

Wenn BufferPoolCommitTargetMB / BufferPoolCommittedMBgrößer als 1 ist, verwendet der Server nicht den gesamten Pufferpool. Wenn die betreffende Maschine auch einen PLE von mehr als "x" hat, ist dies möglicherweise ein guter Kandidat für eine Verringerung von max server memory (mb).

Da der Buffer Manager:Lazy writes/secLeistungsindikator nachverfolgt, wie oft SQLOS aufgrund des Speicherdrucks Seiten zwischen Checkpoints auf die Festplatte geschrieben hat, ist dies möglicherweise eine weitere gute Sache.

DECLARE @WaitTime DATETIME;
SET @WaitTime = '00:00:15';
DECLARE @NumSeconds INT;
SET @NumSeconds = DATEDIFF(SECOND, 0, @WaitTime);
DECLARE @LazyWrites1 BIGINT;
DECLARE @LazyWrites2 BIGINT;

SELECT @LazyWrites1 = cntr_value 
FROM sys.dm_os_performance_counters dopc
WHERE (
        dopc.counter_name LIKE 'Lazy writes/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    )
    AND dopc.object_name = 'MSSQL$' + CONVERT(VARCHAR(255),
               SERVERPROPERTY('InstanceName')) + ':Buffer Manager';

WAITFOR DELAY @WaitTime;

SELECT @LazyWrites2 = cntr_value 
FROM sys.dm_os_performance_counters dopc
WHERE (
        dopc.counter_name LIKE 'Lazy writes/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    )
    AND dopc.object_name = 'MSSQL$' + CONVERT(VARCHAR(255),
               SERVERPROPERTY('InstanceName')) + ':Buffer Manager';

SELECT LazyWritesPerSecond = (@LazyWrites2 - @LazyWrites1) / @NumSeconds;

Bei dem obigen Code wird davon ausgegangen, dass der Server während der 15 Sekunden, die für die Ausführung benötigt werden, ausgelastet ist. Andernfalls wird 0 gemeldet. Das könnte eine irreführende falsch-negative sein.

Sollte ich auch PAGELATCHIO_*Wartestatistiken oder einen anderen Wartetyp als Indikator für den Speicherdruck oder einen Mangel daran betrachten?

Meine Frage ist, wie kann ich einen "guten" Zielwert für PLE und zuverlässig ermitteln max server memory (mb)?

Antworten:


11

Wie Sie bereits wissen, gibt es keine allgemeine Formel zur Berechnung des maximalen Arbeitsspeichers auf dem Server. Sie können schnell rechnen und einen Wert erreichen. Sie benötigen jedoch die Hilfe von Perfmon-Zählern, um die Speichernutzung zu überwachen und entsprechend zu ändern. Ich kenne unten die allgemeine Formel und benutze sie auch. Ich habe diese Formel von This Link gelernt

Für SQL Server 2005 bis 2008 R2

Beachten Sie, dass der maximale Serverspeicher von SQL Server 2005 bis 2008 R2 nur den Pufferpool steuert. Die maximale Speicherkonfiguration des Servers ist hier also etwas mühsam und erfordert nur wenige Berechnungen

  1. Lassen Sie 2 GB Speicher für Windows-Betriebssysteme sofort frei.

  2. Natürlich würde auf dem System Antivirus laufen. Bitte lassen Sie 1.5G für Antivirus. Bitte beachten Sie, dass McAfee und SQL Server nicht Hand in Hand gehen. Sie können auch den Leistungsindikator überprüfen Perfmon Process-> Private bytes and Working Set, um die Speichernutzung durch AV und andere kleine Anwendungen zu überwachen, die auf der SQL Server-Box ausgeführt werden

Bildbeschreibung hier eingeben

  1. Berücksichtigen Sie die Speicheranforderungen der Treiber / Firmwares. Sie müssen sie basierend auf den Speicheranforderungen der auf dem System installierten Treiber ableiten. RAMMAP-Tool kann helfen

  2. Berücksichtigen Sie die Speicheranforderungen von NonbPool (auch bekannt als MTL oder MTR) für SQL Server.

    select  sum(multi_pages_kb)/1024 as multi_pages_mb from  sys.dm_os_memory_clerks

    + Max Worker-Threads * 2 MB

    + Speicher für direkte Windows-Zuweisungen in den meisten Fällen ca. 0 bis 300 MB, muss jedoch möglicherweise erhöht werden, wenn im SQL Server-Prozess viele Komponenten von drei Anbietern geladen sind (einschließlich DLLs für Verbindungsserver, Backup-DLLs von Drittanbietern usw.).

    + Wenn Sie CLR intensiv verwenden, fügen Sie zusätzlichen Speicher für CLR hinzu.

  3. Berücksichtigen Sie den Speicherbedarf nach Aufträgen (einschließlich Replikationsagenten, Protokollversand usw.) und Paketen, die auf dem Server ausgeführt werden. Es kann je nach Anzahl der ausgeführten Jobs von MB zu GB variieren. Für mittelgroße Server können Sie es als 250 MB nehmen

  4. Stellen Sie sicher, dass genügend freier Speicherplatz für das Betriebssystem vorhanden ist.

    Ungefähr (100 MB für jedes GB bis 4 GB) + (50 MB für jedes weitere GB bis 12 GB) + (25 MB für jedes weitere GB bis zu Ihrer RAM-Größe)

  5. Andere Speicheranforderungen.

    Wenn Sie einen anderen Speicherbedarf haben, der für Ihre Umgebung spezifisch ist.

    Maximaler Serverspeicher = Gesamter physischer Speicher - (1 + 2 + 3 + 4 + 5 + 6 + 7)

    Ich habe die Speicherkonfiguration für SSIS.SSRS, SSAS nicht eingeschlossen. Sie müssten auch den von diesen Diensten benötigten Speicher vom gesamten physischen Serverspeicher subtrahieren.

    Nachdem Sie oben konfiguriert haben, müssen Sie die folgenden Zähler überwachen

  • SQLServer: Buffer Manager - Seitenlebenserwartung (PLE):

  • SQLServer: Puffermanager - CheckpointPages / Sek .:

  • SQLServer: Memory Manager - Speicherzuweisungen ausstehend:

  • SQLServer: Speichermanager - Zielserverspeicher:

  • SQLServer: Speichermanager - Gesamter Serverspeicher

Für SQL Server 2012/2014.

From SQL Server 2012 onwardsDas Einrichten des maximalen Serverspeichers ist einfach geworden. Denn jetzt macht der maximale Serverspeicher fast den gesamten Speicherverbrauch aus. Der maximale Serverspeicher steuert die SQL Server-Speicherzuordnung, einschließlich des Pufferpools, des Kompilierungsspeichers, aller Caches, der Speicherzuweisungen, des Speichers des Sperrenmanagers und des CLR-Speichers (im Grunde jeder „Angestellte“, der in dm_os_memory_clerks enthalten ist). Der Speicher für Thread-Stapel, Heaps, andere Verbindungsserver-Anbieter als SQL Server oder von einer Nicht-SQL Server-DLL zugewiesenen Speicher wird nicht vom maximalen Serverspeicher gesteuert.

Sie können SQL Server 75-80% zuweisen und dann mithilfe von Leistungsindikatoren die Speichernutzung überwachen. In SQL Server 2012 sind nur wenige Leistungsindikatoren veraltet. Der Puffermanagerzähler ist veraltet. Sie müssen den Speichermanagerzähler verwenden

  • SQL Server: Memory Manager - Zielserverspeicher (KB)

  • SQL Server: Speichermanager - Gesamter Serverspeicher (KB)

  • SQL Server: Memory Manager - Freier Speicher (KB)

  • SQL Server: Speichermanager - Datenbank-Cache-Speicher (KB)

Auf den Wert von PLE habe ich Formel von Joanthan verwendet und zum Glück hat es für mich funktioniert.


6

Die Herausforderung dabei ist, dass Zahlen die Endbenutzererfahrung nicht berücksichtigen.

Tolles Beispiel: Ich habe einen Datenbankserver verwendet, um jede Website zu verfolgen, die die Mitarbeiter des Unternehmens besuchen. Es ist mir egal, ob es bei Spitzenlasten nicht mit Beilagen mithalten kann, da die Front-End-App die Beilagen regelmäßig stapelt und langsame Beilagen für Benutzer kein Problem darstellen. Benutzer können weiterhin im Internet surfen, ohne von langsamen Einfügungen aufgehalten zu werden.

Zur SELECT-Zeit gibt die Personalabteilung nur Berichte aus, wenn sie nach verdächtigem Browserverlauf für einen bestimmten Mitarbeiter gefragt wird, aber es ist ihnen egal, wie lange die Berichte dauern - sie öffnen nur den Bericht und gehen zu anderen Aufgaben über.

Die Leistung muss mit einer Frage beginnen: Sind die Benutzer mit der Leistung zufrieden? Wenn ja, lassen Sie das System dort, wo es ist.


Auch wenn Sie mehr Speicher benötigen als nötig?
James Anderson

2
James - im Allgemeinen möchte ich keine Änderungen vornehmen, die Benutzer dazu bringen, sich zu beschweren. Wenn Sie dies tun möchten, können Sie den Arbeitsspeicher für jeden Server schrittweise verringern, bis sich die Benutzer beschweren. Wenn ich jedoch bereits überarbeitet bin, habe ich im Allgemeinen keine Zeit, diese Schritte auszuführen. Ich muss mich auf die Aufgaben konzentrieren, die unglückliche Benutzer glücklich machen - anstatt zu versuchen, glückliche Benutzer unglücklich zu machen. ;-)
Brent Ozar

2
Gute Punkte, Brent. Ich wurde gefragt, ob einige Server überlastet sind, da wir für Speicher pro GB und Jahr zahlen. Viele der von mir betrachteten Instanzen haben, wie ich finde, einen sehr kleinen RAM-Speicher max server memory (mb), und daher zögere ich es ziemlich, sie zu verkleinern. Einige andere Instanzen haben jedoch mehr als 1.000.000 PLE und sind daher ziemlich offensichtliche potenzielle Kandidaten für einen RAM-Rückgang. Offensichtlich RAM Senkung wird eine Erhöhung der IOps verursachen, und ich bin nicht sicher , was die Kosten für das sein wird.
Max Vernon

1
Außerdem max server memoryist es eine Art Henne-Ei-Sache, PLE im Vergleich zum Setting zu betrachten. max server memoryJe niedriger die Einstellung, desto niedriger ist der minimale "akzeptable" PLE, sodass ich in einer immer tiefer werdenden Spirale stecken bleiben könnte. Ich bin mir sicher, dass, wie Sie bereits erwähnt haben, die Leistung der Benutzer irgendwann beeinträchtigt sein wird.
Max Vernon

PLE-Zähler sollten Sie ab 2012 oder bei einem NUMA-System vermeiden, bei dem sich jeder Knoten als eigener kleiner Speicherzuordner verhält. Wenn Sie möchten, sollten Sie nach PLE für jeden NUMA-Knoten suchen, der nicht vollständig ist. Möglicherweise wird ein falscher Wert
angezeigt

3

Das aktuelle T-SQL, mit dem ich PLE vs auswerte, max server memoryist:

/*
    Purpose:            Returns a resultset describing various server level stats including PLE
                        Max and Min Server Memory, etc.
    By:                 Max Vernon
    Date:               2014-12-01
*/
SET NOCOUNT ON;

/*
    wait stats for PAGELATCH_IO
*/
DECLARE @Debug BIT;
SET @Debug = 0;
DECLARE @HTMLOutput BIT;
SET @HTMLOutput = 1;
DECLARE @WaitTime DATETIME;
SET @WaitTime = '00:00:15';
DECLARE @NumSeconds INT;
SET @NumSeconds = DATEDIFF(SECOND, 0, @WaitTime);
DECLARE @InstanceName NVARCHAR(255);
SET @InstanceName = CONVERT(NVARCHAR(255), SERVERPROPERTY('InstanceName'));
DECLARE @Version NVARCHAR(255);
DECLARE @VersionINT INT;
SET @Version = CONVERT(NVARCHAR(255),SERVERPROPERTY('ProductVersion'));
SET @VersionINT = CONVERT(INT, SUBSTRING(@Version,1 ,CHARINDEX('.',@Version)-1));
DECLARE @cmd NVARCHAR(MAX);
SET @cmd = '';
DECLARE @TaskCount INT;
DECLARE @TasksPerSecondAvg INT;
DECLARE @AvgWaitTimeInMSPerTask DECIMAL(10,2);
DECLARE @AvgWaitTimeInMSPerSecond DECIMAL(10,2);
DECLARE @TotalWaitTimeInMSOverall DECIMAL(10,2);
DECLARE @LazyWrites1 BIGINT;
DECLARE @LazyWrites2 BIGINT;
DECLARE @FreeListStallsSec1 BIGINT;
DECLARE @FreeListStallsSec2 BIGINT;
DECLARE @BatchReq1 BIGINT;
DECLARE @BatchReq2 BIGINT;
DECLARE @ws TABLE
(
    RunNum INT
    , wait_type SYSNAME
    , waiting_tasks_count BIGINT
    , wait_time_ms BIGINT
    , max_wait_time_ms BIGINT
    , signal_wait_time_ms BIGINT
);
INSERT INTO @ws
SELECT 1, dows.*
FROM sys.dm_os_wait_stats dows
WHERE dows.wait_type LIKE 'PAGEIOLATCH_%'
ORDER BY dows.waiting_tasks_count DESC;

SELECT @LazyWrites1 = cntr_value 
FROM sys.dm_os_performance_counters dopc
WHERE (
        dopc.counter_name LIKE N'Lazy writes/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    )
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':Buffer Manager';

SELECT @FreeListStallsSec1 = cntr_value 
FROM sys.dm_os_performance_counters dopc
WHERE (
        dopc.counter_name LIKE N'Free list stalls/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    )
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':Buffer Manager';

SELECT @BatchReq1 = cntr_value
FROM sys.dm_os_performance_counters dopc
WHERE dopc.counter_name LIKE N'Batch Requests/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':SQL Statistics';

WAITFOR DELAY @WaitTime;

INSERT INTO @ws
SELECT 2, dows.*
FROM sys.dm_os_wait_stats dows
WHERE dows.wait_type LIKE N'PAGEIOLATCH_%'
ORDER BY dows.waiting_tasks_count DESC;

SELECT @LazyWrites2 = cntr_value 
FROM sys.dm_os_performance_counters dopc
WHERE (
        dopc.counter_name LIKE N'Lazy writes/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    )
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':Buffer Manager';

SELECT @FreeListStallsSec2 = cntr_value 
FROM sys.dm_os_performance_counters dopc
WHERE (
        dopc.counter_name LIKE N'Free list stalls/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    )
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':Buffer Manager';

SELECT @TaskCount = SUM(w2.waiting_tasks_count - w1.waiting_tasks_count)
    , @TasksPerSecondAvg = CONVERT(DECIMAL(10,2), (SUM(w2.waiting_tasks_count) - SUM(w1.waiting_tasks_count))) / @NumSeconds
    , @AvgWaitTimeInMSPerTask = CONVERT(DECIMAL(10,2),(SUM(w2.wait_time_ms) - SUM(w1.wait_time_ms))) / CONVERT(DECIMAL(10,2),(SUM(w2.waiting_tasks_count) - SUM(w1.waiting_tasks_count)))
    , @AvgWaitTimeInMSPerSecond = (CONVERT(DECIMAL(10,2), (SUM(w2.waiting_tasks_count) - SUM(w1.waiting_tasks_count))) / @NumSeconds) * (CONVERT(DECIMAL(10,2),(SUM(w2.wait_time_ms) - SUM(w1.wait_time_ms))) / CONVERT(DECIMAL(10,2),(SUM(w2.waiting_tasks_count) - SUM(w1.waiting_tasks_count))))
    , @TotalWaitTimeInMSOverall = SUM(w2.wait_time_ms) - SUM(w1.wait_time_ms)
FROM (SELECT * FROM @ws ws1 WHERE ws1.RunNum = 1) w1
    INNER JOIN (SELECT * FROM @ws ws2 WHERE ws2.RunNum = 2) w2 ON w1.wait_type = w2.wait_type
WHERE (w2.waiting_tasks_count - w1.waiting_tasks_count) > 0;

SELECT @BatchReq2 = cntr_value
FROM sys.dm_os_performance_counters dopc
WHERE dopc.counter_name LIKE N'Batch Requests/sec%' COLLATE SQL_Latin1_General_CP1_CI_AS
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':SQL Statistics';

/*
    configured values for max server memory and min server memory, etc
*/
DECLARE @MaxServerMemory BIGINT;
DECLARE @MaxServerMemoryPages BIGINT;
DECLARE @MinServerMemory BIGINT;
DECLARE @MinPLE BIGINT;
DECLARE @RamMB BIGINT;
DECLARE @BufferPoolCommittedMB BIGINT;
DECLARE @BufferPoolCommitTargetMB BIGINT;
DECLARE @PercentOfDesiredSizeMB INT;
DECLARE @TargetPageLifeExpectancyPer4GB BIGINT;
SET @TargetPageLifeExpectancyPer4GB = 60 * 120; /* 120 minutes */
/*DECLARE @VMType VARCHAR(255);*/
DECLARE @PLESeconds BIGINT;

SELECT @MaxServerMemory = CONVERT(BIGINT,c.value)
FROM sys.configurations c
WHERE c.name = N'max server memory (mb)'

SET @MaxServerMemoryPages = @MaxServerMemory / 128; /* 8KB pages */

SELECT @MinServerMemory = CONVERT(BIGINT,c.value)
FROM sys.configurations c
WHERE c.name = N'min server memory (mb)'

SET @MinPLE = @MaxServerMemory / 4096E0 * @TargetPageLifeExpectancyPer4GB;

IF @VersionINT < 11
BEGIN
    SET @cmd = 'SELECT 
    @RamMB = dosi.physical_memory_in_bytes / 1048576
    , @BufferPoolCommittedMB = dosi.bpool_committed * 8192E0 / 1048576
    , @BufferPoolCommitTargetMB = dosi.bpool_commit_target * 8192E0 / 1048576
    , @PercentOfDesiredSizeMB = CONVERT(INT,(CONVERT(DECIMAL(18,2),dosi.bpool_committed) / dosi.bpool_commit_target) * 100)
FROM sys.dm_os_sys_info dosi;
';
END
ELSE 
BEGIN 
SET @cmd = 'SELECT 
    @RamMB = dosi.physical_memory_kb / 1024
    , @BufferPoolCommittedMB = dosi.committed_kb / 1024
    , @BufferPoolCommitTargetMB = dosi.committed_target_kb / 1024
    , @PercentOfDesiredSizeMB = CONVERT(INT,(CONVERT(DECIMAL(18,2),dosi.committed_kb) / dosi.committed_target_kb) * 100)
FROM sys.dm_os_sys_info dosi;';
END
EXEC sp_executesql @cmd
    , N'@RamMB BIGINT OUTPUT, @BufferPoolCommittedMB BIGINT OUTPUT, @BufferPoolCommitTargetMB BIGINT OUTPUT, @PercentOfDesiredSizeMB INT OUTPUT' 
    , @RamMB = @RamMB OUT
    , @BufferPoolCommittedMB = @BufferPoolCommittedMB OUT
    , @BufferPoolCommitTargetMB = @BufferPoolCommitTargetMB OUT
    , @PercentOfDesiredSizeMB = @PercentOfDesiredSizeMB OUT;

/*
    Page Life Expectancy for all memory nodes
*/
SELECT @PLESeconds = CONVERT(BIGINT, cntr_value) 
FROM sys.dm_os_performance_counters dopc
WHERE dopc.counter_name LIKE N'Page Life Expectancy%' COLLATE SQL_Latin1_General_CP1_CI_AS
    AND dopc.object_name = N'MSSQL$' + @InstanceName + N':Buffer Manager';

/*
    Total data in all user-databases.
*/
DECLARE @TotalDBSpaceUsed TABLE
(
    TotalSpaceUsedInMB BIGINT
);
DECLARE @SpaceUsedInMB BIGINT;
SET @cmd = '';
SELECT @cmd = @cmd + CASE WHEN @cmd = '' THEN '' ELSE '
UNION ALL
' END + 
'
SELECT DatabaseName = ''' + d.name + ''' 
    , AllocType = au.type_desc
    , TotalPagesInMB = SUM(au.total_pages) * 8192E0 / 1048576
FROM ' + QUOTENAME(d.name) + '.sys.allocation_units au
WHERE au.type > 0
GROUP BY au.type_desc
'
FROM master.sys.databases d
WHERE d.database_id > 4;
SET @cmd = 'SELECT SUM(TotalPagesInMB)
FROM (
' + @cmd + '
) t;'; 
INSERT INTO @TotalDBSpaceUsed (TotalSpaceUsedInMB)
EXEC sp_executesql @cmd;
SELECT @SpaceUsedInMB = TDSU.TotalSpaceUsedInMB
FROM @TotalDBSpaceUsed TDSU;

IF @Debug = 1
BEGIN
    SELECT ServerName = @@SERVERNAME
        , InstanceName = @InstanceName
        , DatabaseSpaceUsedMB = @SpaceUsedInMB
        , PLEinSeconds = @PLESeconds
        , MinAcceptablePLE = @MinPLE
        , MinServerMemoryMB = @MinServerMemory
        , MaxServerMemoryMB = @MaxServerMemory
        , TotalServerRAMinMB = @RamMB
        , BufferPoolCommittedMB = @BufferPoolCommittedMB
        , BufferPoolCommitTargetMB = @BufferPoolCommitTargetMB
        , PercentBufferPoolCommitted = @PercentOfDesiredSizeMB
        , BatchReqPerSecond = (@BatchReq2 - @BatchReq1) / @NumSeconds
        , LazyWritesPerSecond = (@LazyWrites2 - @LazyWrites1) / @NumSeconds
        , FreeListStallsPerSecond = (@FreeListStallsSec2 - @FreeListStallsSec2) / @NumSeconds
        /*, VMType = @VMType*/
        , IOTaskCount = @TaskCount 
        , TaskPerSecondAvg = @TasksPerSecondAvg 
        , AvgWaitTimeInMSPerTask = @AvgWaitTimeInMSPerTask 
        , AvgWaitTimeInMSPerSecond = @AvgWaitTimeInMSPerSecond 
        , TotalWaitTimeInMSOverall  = @TotalWaitTimeInMSOverall
        , SamplePeriodinSec = @NumSeconds;

    SELECT MaxServerMemorySuggested = 
            CASE WHEN @BufferPoolCommittedMB < @BufferPoolCommitTargetMB 
            THEN @BufferPoolCommittedMB 
            ELSE ((CONVERT(DECIMAL(18,4), @MinPLE) / @PLESeconds) * @MaxServerMemory) 
                    + (((@LazyWrites2 - @LazyWrites1) / @NumSeconds) * 64) 
                    + ((@FreeListStallsSec2 - @FreeListStallsSec2) / @NumSeconds) * 64 
            END
        , Reason = CASE WHEN @BufferPoolCommittedMB < @BufferPoolCommitTargetMB THEN N'Committed MB less than current Max Server Memory'
            ELSE N'Calculated based on PLE, Lazy Writes / second and List Stalls / second' END
        , LazyWritesX64 = (((@LazyWrites2 - @LazyWrites1) / @NumSeconds) * 64)
        , ListStallsX64 = ((@FreeListStallsSec2 - @FreeListStallsSec2) / @NumSeconds) * 64;
END

DECLARE @Out TABLE
(
    KeyID INT IDENTITY(1,1)
    , ItemDesc NVARCHAR(255)
    , ItemValue SQL_VARIANT
    , IsDebug BIT DEFAULT(0)
);

INSERT INTO @Out (ItemDesc, ItemValue, IsDebug)
VALUES (N'Server Name', CONVERT(NVARCHAR(255),@@SERVERNAME), 1);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Data Space Used (MB)', @SpaceUsedInMB);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Page Life Expectancy (sec)', @PLESeconds);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Minimum Acceptable Page Life Expectancy (sec)', @MinPLE);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Minimum Server Memory (MB)', @MinServerMemory);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Maximum Server Memory (MB)', @MaxServerMemory);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Total Server RAM in MB', @RamMB);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Buffer Pool Committed MB', @BufferPoolCommittedMB);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Buffer Pool Commit Target MB', @BufferPoolCommitTargetMB);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Percent of Buffer Pool Committed', @PercentOfDesiredSizeMB);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Batch Requests Per Second', (@BatchReq2 - @BatchReq1) / @NumSeconds);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Lazy Writes Per Second', (@LazyWrites2 - @LazyWrites1) / @NumSeconds);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Free List Stalls Per Second', (@FreeListStallsSec2 - @FreeListStallsSec2) / @NumSeconds);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'IO Task Count', @TaskCount);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Task Per Second Avg', @TasksPerSecondAvg);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Avg Wait Time In MS Per Task', @AvgWaitTimeInMSPerTask);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Avg Wait Time In MS Per Second', @AvgWaitTimeInMSPerSecond);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Total Wait Time In MS Overall', @TotalWaitTimeInMSOverall);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Sample Period in Seconds', @NumSeconds);

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Lazy Writes per Second', ((@LazyWrites2 - @LazyWrites1) / @NumSeconds));

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'List Stalls per Second', ((@FreeListStallsSec2 - @FreeListStallsSec2) / @NumSeconds));

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Recommended Max Memory (MB)', N'');

INSERT INTO @Out (ItemDesc, ItemValue)
VALUES (N'Recommended Max Memory Reason', N'');

INSERT INTO @Out (ItemDesc, ItemValue, IsDebug)
VALUES (N'Recommended Max Memory Signal', 0, 1);

/*
    Add memory if Lazy Writes occurred
    Add 64MB per Lazy Write (just for fun)
*/
DECLARE @LazyWritesMB INT;
SET @LazyWritesMB = (((@LazyWrites2 - @LazyWrites1) / @NumSeconds) * 64);

/*
    Add memory if Free List Stalls occurred
    Add 128MB per Free List Stall
*/
DECLARE @FreeListStallMB INT;
SET @FreeListStallMB = (((@FreeListStallsSec2 - @FreeListStallsSec2) / @NumSeconds) * 128);

/*
    Add the Additional memory requirements to the Recommended Max Memory row
*/
DECLARE @AdditionalMemory INT;
SET @AdditionalMemory = 
    @LazyWritesMB
    + @FreeListStallMB;

IF (@MaxServerMemory + @AdditionalMemory < 1024) AND (@PLESeconds >= @MinPLE)
BEGIN
    UPDATE @Out 
    SET ItemValue = @MaxServerMemory
    WHERE ItemDesc = N'Recommended Max Memory (MB)';

    UPDATE @Out 
    SET ItemValue = 'Max Server Memory is low, however PLE is acceptable'
    WHERE ItemDesc = N'Recommended Max Memory Reason';

    UPDATE @Out 
    SET ItemValue = 1
    WHERE ItemDesc = N'Recommended Max Memory Signal';
END

IF ((@BufferPoolCommittedMB + @AdditionalMemory) < @BufferPoolCommitTargetMB) AND (@PLESeconds >= @MinPLE)
BEGIN
    UPDATE @Out 
    SET ItemValue = @BufferPoolCommittedMB + @AdditionalMemory
    WHERE ItemDesc = N'Recommended Max Memory (MB)';

    UPDATE @Out 
    SET ItemValue = 'Buffer pool committed is less than Max Server Memory, and PLE is acceptable.'
    WHERE ItemDesc = N'Recommended Max Memory Reason';

    UPDATE @Out 
    SET ItemValue = 2
    WHERE ItemDesc = N'Recommended Max Memory Signal';
END

DECLARE @PLEMultiplier DECIMAL(10,2);
SET @PLEMultiplier = (CONVERT(DECIMAL(10,2),@MinPLE) / CONVERT(DECIMAL(10,2), @PLESeconds));
IF @PLEMultiplier < 0.90 SET @PLEMultiplier = 0.90;
IF @PLEMultiplier > 1.10 SET @PLEMultiplier = 1.10;

INSERT INTO @Out (ItemDesc, ItemValue, IsDebug)
VALUES (N'PLE Multiplier', @PLEMultiplier, 1);

IF /*(@MaxServerMemory + @AdditionalMemory >= 1024) AND*/ (@PLESeconds <= @MinPLE)
BEGIN
    UPDATE @Out 
    SET ItemValue = 
        (SELECT TOP(1) Inc
        FROM (
            SELECT Inc = t.RowNum * 256
            FROM (
                SELECT RowNum = CONVERT(BIGINT,ROW_NUMBER() OVER (ORDER BY o.object_id))
                FROM sys.objects o, sys.objects o1
                ) t
            WHERE (t.RowNum * 256) <  CONVERT(BIGINT,POWER(2,30))
            ) t1
        WHERE t1.Inc > CONVERT(INT, (@MaxServerMemory * @PLEMultiplier))
        ORDER BY t1.Inc)
    WHERE ItemDesc = N'Recommended Max Memory (MB)';

    UPDATE @Out 
    SET ItemValue = 'Low PLE indicates Max Server Memory should be adjusted upwards.'
    WHERE ItemDesc = N'Recommended Max Memory Reason';

    UPDATE @Out 
    SET ItemValue = 3
    WHERE ItemDesc = N'Recommended Max Memory Signal';
END

IF (@MaxServerMemory + @AdditionalMemory >= 1024) AND (@PLESeconds > @MinPLE)
BEGIN
    UPDATE @Out 
    SET ItemValue = 
        (SELECT TOP(1) Inc
        FROM (
            SELECT Inc = t.RowNum * 256
            FROM (
                SELECT RowNum = CONVERT(BIGINT,ROW_NUMBER() OVER (ORDER BY o.object_id))
                FROM sys.objects o, sys.objects o1
                ) t
            WHERE (t.RowNum * 256) <  CONVERT(BIGINT,POWER(2,30))
            ) t1
        WHERE t1.Inc <= CONVERT(INT, (@MaxServerMemory * @PLEMultiplier))
        ORDER BY t1.Inc DESC)
    WHERE ItemDesc = N'Recommended Max Memory (MB)';

    UPDATE @Out 
    SET ItemValue = 'High PLE indicates Max Server Memory could be adjusted downwards.'
    WHERE ItemDesc = N'Recommended Max Memory Reason';

    UPDATE @Out 
    SET ItemValue = 4
    WHERE ItemDesc = N'Recommended Max Memory Signal';
END

DECLARE @RecommendedMaxServerMemory INT;
SELECT  @RecommendedMaxServerMemory = CONVERT(INT,ItemValue)
FROM @Out o 
WHERE o.ItemDesc = N'Recommended Max Memory (MB)';

IF @RecommendedMaxServerMemory > (@MaxServerMemory * 0.96)
    AND @RecommendedMaxServerMemory < (@MaxServerMemory * 1.04)
BEGIN
    UPDATE @Out
    SET ItemValue = @MaxServerMemory
    WHERE ItemDesc = N'Recommended Max Memory (MB)';
    UPDATE @Out
    SET ItemValue = 'No changed recommended'
    WHERE ItemDesc = N'Recommended Max Memory Reason';
    UPDATE @Out 
    SET ItemValue = 0
    WHERE ItemDesc = N'Recommended Max Memory Signal';
END 

IF (@HTMLOutput = 1)
BEGIN
    SELECT ItemValue
        , HTMLOutput = '<table>' + 
            (
                SELECT 'td' = ItemDesc
                    , ''
                    , 'td' = ItemValue
                    , ''
                FROM @Out o
                WHERE CASE WHEN @Debug = 0 THEN o.IsDebug ELSE 0 END = 0
                ORDER BY o.KeyID
                FOR XML PATH('tr')
            ) +
            '</table>'
    FROM @Out o
    WHERE o.ItemDesc = N'Recommended Max Memory Signal';
END
ELSE
BEGIN
    SELECT *
    FROM @Out o
    WHERE CASE WHEN @Debug = 0 THEN o.IsDebug ELSE 0 END = 0
    ORDER BY o.KeyID;
END

Dieser Code vergleicht die PLE mit einer minimalen "akzeptablen" PLE für die Menge, die max server memorydas System konfiguriert hat. Wenn der PLE merklich höher als die akzeptable Zahl ist, schlägt er ein Maximum von 10% niedriger vor max server memory. Wenn der PLE niedriger als der akzeptable PLE ist, werden maximal 10% mehr vorgeschlagen max server memory.

Wenn die tatsächliche Größe des zugesicherten Pufferpools geringer ist als die Größe des Zielpufferpools, wird eine Reduzierung max server memoryauf diese Größe sowie zusätzlicher Speicher für Threads, verzögerte Schreibvorgänge usw. empfohlen.

Der Code untersucht auch verschiedene Leistungsindikatoren für Dinge wie Lazy Writes / second, Free List Stalls und Batch Requests.

Der Code ist nicht perfekt. Ich teile ihn hier, um Eingaben zu erhalten und zum Nutzen zukünftiger SO-Benutzer.


1
Max Mind Sie ab SQL Server 2012 Buffer Pool-Ziel und festgeschrieben hat keinen Sinn und diese Leistungsindikatoren sind veraltet. Stattdessen müssen Sie Memory Manager Target Committed (KB) und Current Committed verwenden. Wenn Sie mehr lesen wollen , warum gibt es einen falschen Wert social.technet.microsoft.com/wiki/contents/articles/...
Shanky
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.