Qual è un metodo deterministico per valutare una dimensione sensibile del pool di buffer?


29

Sto cercando di escogitare un modo sano per capire se l' max server memory (mb)impostazione è appropriata (o dovrebbe essere più bassa o più alta o rimanere così). Sono consapevole che max server memory (mb)dovrebbe essere sempre abbastanza basso da lasciare spazio al sistema operativo stesso, ecc.

L'ambiente che sto guardando ha diverse centinaia di server; Ho bisogno di una formula affidabile che posso usare per determinare se la dimensione attuale del pool di buffer è appropriata poiché la RAM è costata per GB assegnato a ciascun server. L'intero ambiente è virtualizzato e la RAM "fisica" allocata a una VM può essere facilmente modificata su o giù.

Ho una particolare istanza di SQL Server che sto esaminando ora con un PLE di 1.100.052 secondi, che equivale a 12,7 giorni (la quantità di tempo in cui il server è stato attivo). Il server ha un'impostazione di memoria massima del server di 2560 MB (2,5 GB), di cui solo 1380 MB (1,3 GB) sono effettivamente impegnati.

Ho letto diversi articoli tra cui uno di Jonathan Keheyias ( post ) e un altro di Paul Randal ( post ), e molti altri. Jonathan sostiene che il monitoraggio di un PLE inferiore a 300 per 4 GB di pool di buffer sia troppo basso. Per l'istanza di SQL Server sopra, 300 * (2.5 / 4) = 187risulta un PLE target davvero molto basso inferiore a 300. Questa istanza ha 290 GB di dati di SQL Server (esclusi i file di registro) e viene utilizzata solo per i test di integrazione. Supponendo che gli ultimi 12 giorni siano rappresentativi dell'utilizzo tipico di questo server, direi che l' max server memory (mb)impostazione potrebbe essere ridotta.

All'altra estremità della scala, ho un altro server di test di integrazione con un PLE di 294, che ha max server memory (mb)un'impostazione di solo 1 GB. Questo server ha solo 224 MB di dati di SQL Server esclusi i log e sta eseguendo alcuni database BizFlow. Questo server potrebbe beneficiare di un'impostazione più elevata max server memory (mb).

Sto pensando a un buon punto di partenza per obiettivi a cui potrebbe essere assegnata troppa memoria che potrebbe includere la ricerca di:

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;

Se BufferPoolCommitTargetMB / BufferPoolCommittedMBè maggiore di 1, il server non utilizza l'intero pool di buffer. Se la macchina in questione ha anche un PLE maggiore di "x", potrebbe essere un buon candidato per una riduzione di max server memory (mb).

Poiché il Buffer Manager:Lazy writes/seccontatore delle prestazioni tiene traccia del numero di volte in cui SQLOS ha scritto le pagine sul disco tra i punti di controllo a causa della pressione della memoria, questa potrebbe essere un'altra cosa utile da considerare.

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;

Il codice sopra riportato presuppone che il server sia sotto carico durante i 15 secondi necessari per l'esecuzione, altrimenti riporterà 0; che potrebbe essere un falso negativo fuorviante.

Dovrei anche guardare le PAGELATCHIO_*statistiche di attesa o qualche altro tipo di attesa come un indicatore della pressione della memoria o della sua mancanza?

La mia domanda è: come posso determinare in modo affidabile un valore target "buono" per PLE e max server memory (mb)?

Risposte:


11

Come già sapete, non esiste una formula generale per calcolare la memoria massima del server, è possibile eseguire alcuni calcoli rapidi e raggiungere un valore, ma sarebbe comunque necessario l'aiuto dei contatori Perfmon per monitorare l'utilizzo della memoria e modificare di conseguenza. Conosco di seguito la formula generale e la uso anche io. Ho imparato questa formula da questo link

Per SQL Server 2005 a 2008 R2

Nota: da SQL Server 2005 a 2008 la memoria massima del server R2 controlla solo il pool di buffer. Quindi la configurazione massima della memoria del server è un po 'noiosa qui e comporta pochi calcoli

  1. Lascia subito 2 G di memoria per il sistema operativo Windows.

  2. Naturalmente il sistema avrebbe un antivirus in esecuzione. Si prega di lasciare 1.5G per antivirus. Nota: Mcafee e SQL Server non vanno di pari passo, quindi assicurati di lasciarne abbastanza. È inoltre possibile controllare il contatore perfmon Perfmon Process-> Private bytes and Working Setper monitorare l'utilizzo della memoria da parte di AV e altre piccole applicazioni in esecuzione su SQL Server

inserisci qui la descrizione dell'immagine

  1. Considerare i requisiti di memoria dei driver / firmware. È necessario ricavarli in base ai requisiti di memoria dei driver installati sul sistema. Lo strumento RAMMAP può essere d'aiuto

  2. Considerare i requisiti di memoria NonbPool (aka MTL o MTR) di SQL Server.

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

    + Numero massimo di thread di lavoro * 2 MB

    + Memoria per allocazioni dirette di Windows da 0 a 300 MB circa nella maggior parte dei casi, ma potrebbe essere necessario aumentarlo se ci sono molti componenti di 3 parti caricati nel processo di SQL Server (inclusi dll di server collegati, dll di backup di terze parti ecc.)

    + Se si utilizza CLR, aggiungere un po 'di memoria aggiuntiva per CLR.

  3. Considerare i requisiti di memoria per i lavori (inclusi agenti di replica, invio log ecc.) E pacchetti che verranno eseguiti sul server. Può molto da MB a GB in base al numero di lavori in esecuzione. Per server di medie dimensioni puoi prenderlo come 250 MB

  4. Assicurarsi che vi sia spazio sufficiente per il sistema operativo.

    Circa (100 MB per ogni GB fino a 4G) + (50 MB per ogni GB aggiuntivo fino a 12 GB) + (25 MB per ogni GB aggiuntivo fino alla dimensione della RAM)

  5. Altri requisiti di memoria.

    Se hai altri requisiti di memoria specifici per il tuo ambiente.

    Memoria massima server = memoria fisica totale - (1 + 2 + 3 + 4 + 5 + 6 + 7)

    Non ho incluso la configurazione della memoria per SSIS.SSRS, SSAS dovresti anche sottrarre la memoria richiesta da questi servizi dalla memoria totale del server fisico.

    Dopo aver configurato in precedenza, è necessario monitorare i seguenti contatori

  • SQL Server: Buffer Manager - Aspettativa di vita della pagina (PLE):

  • SQLServer: Buffer Manager - CheckpointPages / sec:

  • SQL Server: Memory Manager - Memory Grants in sospeso:

  • SQLServer: memory manager - Memoria server di destinazione:

  • SQL Server: memory manager - memoria totale del server

Per SQL Server 2012/2014.

From SQL Server 2012 onwardsla configurazione della memoria massima del server è diventata semplice. Perché ora la memoria massima del server rappresenta quasi tutto il consumo di memoria. La memoria massima del server controlla l'allocazione della memoria di SQL Server, incluso il pool di buffer, la memoria di compilazione, tutte le cache, le autorizzazioni di memoria qe, la memoria del gestore dei blocchi e la memoria CLR (praticamente qualsiasi "impiegato" come si trova in dm_os_memory_clerks). La memoria per stack di thread, heap, provider di server collegati diversi da SQL Server o qualsiasi memoria allocata da una DLL "non SQL Server" non è controllata dalla memoria massima del server.

È possibile allocare il 75-80% a SQL Server e quindi utilizzare i contatori perfmon per monitorare l'utilizzo della memoria. In SQL Server 2012 alcuni contatori perfmon sono stati deprecati. Il contatore del gestore buffer è obsoleto, è necessario utilizzare il contatore del gestore memoria

  • SQL Server: Memory Manager-- Target Server Memory (KB)

  • SQL Server: Memory Manager - Total Server Memory (KB)

  • SQL Server: Memory Manager - Memoria libera (KB)

  • SQL Server: Memory Manager - Database Cache Memory (KB)

Sul valore di PLE, ho usato la formula di Joanthan e fortunatamente ha funzionato per me.


6

La sfida qui è che i numeri non tengono conto dell'esperienza dell'utente finale.

Grande esempio: ho un server di database utilizzato per tracciare tutti i siti Web visitati dai dipendenti dell'azienda. Non mi importa se non riesce a tenere il passo con gli inserti durante i carichi di picco perché l'app front-end esegue il batch periodico degli inserti e gli inserimenti lenti non causano problemi agli utenti. Gli utenti sono ancora in grado di navigare sul Web senza essere ostacolati da inserimenti lenti.

Al momento di SELEZIONARE, il dipartimento Risorse umane lancia semplicemente rapporti quando viene richiesta una cronologia di navigazione sospetta per un determinato dipendente, ma a loro non importa quanto tempo impiegano i rapporti: semplicemente aprono il rapporto e iniziano a fare altre cose.

Le prestazioni devono iniziare con una domanda: gli utenti sono soddisfatti delle prestazioni? In tal caso, lasciare il sistema dov'è.


Anche se stai usando più memoria del necessario?
James Anderson,

2
James - in generale, non voglio apportare modifiche che facciano lamentare gli utenti. Se si desidera farlo, è possibile ridurre gradualmente la quantità di memoria per ciascun server fino a quando gli utenti non iniziano a lamentarsi, ma quando sono già sovraccarico di lavoro, in genere non ho tempo di fare questi passi. Devo concentrarmi sulle attività che renderanno felici gli utenti infelici, piuttosto che cercare di rendere infelici gli utenti felici. ;-)
Brent Ozar l'

2
Buoni punti, Brent. Mi è stato chiesto di verificare se alcuni server sono sottoposti a provisioning eccessivo perché paghiamo la memoria per GB all'anno. Molte delle istanze che sto esaminando hanno quella che considero una quantità molto piccola di RAM max server memory (mb), e come tale sono piuttosto riluttante a ridimensionarle. Tuttavia, alcuni altri casi hanno 1.000.000 + PLE, e come tali sono potenziali candidati abbastanza ovvi per un calo della RAM. Chiaramente, abbassando RAM causerà un aumento di IOPS e non sono sicuro quale sia il costo di che sarà.
Max Vernon,

1
Inoltre, guardare PLE rispetto max server memoryall'ambientazione è una specie di pollo e uovo; più bassa è l' max server memoryimpostazione, minore sarà il PLE minimo "accettabile", così potrei rimanere bloccato in una spirale sempre più bassa. Sono sicuro, come dici tu, che le prestazioni dell'utente saranno influenzate ad un certo punto .
Max Vernon,

I contatori PLE sono quelli che dovresti evitare di guardare dal 2012 in poi o quando hai un sistema NUMA in cui ogni nodo si comporta come allocatore di memoria piccolo. Se vuoi, dovresti cercare PLE per ogni nodo NUMA non completo, potresti ottenere un valore errato
Shanky,

3

L'attuale T-SQL che sto usando per valutare PLE vs max server memoryè:

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

Questo codice confronta il PLE con un PLE minimo "accettabile" per la quantità di max server memorysistema configurata. Se il PLE è sensibilmente superiore al numero accettabile, suggerisce un massimo del 10% inferiore max server memory. Se il PLE è inferiore al PLE accettabile, suggerisce un massimo del 10% in più max server memory.

Se la quantità effettiva di pool di buffer impegnati è inferiore alla dimensione del pool di buffer di destinazione, si suggerisce di ridurlo max server memorya tale importo, oltre ad un po 'di memoria aggiuntiva per thread, scritture lazy, ecc.

Il codice esamina anche vari contatori delle prestazioni per cose come Lazy Writes / second, Free List Stalls e Batch Requests.

Il codice non è perfetto, lo sto condividendo qui per ottenere input e per il beneficio dei futuri utenti SO.


1
Max Mind you a partire dalla destinazione pool di buffer di SQL Server 2012 e impegnati non ha senso e questi contatori sono obsoleti. Invece è necessario utilizzare Memory Manager Target Committed (KB) e il commit corrente. Se vuoi leggere di più perché dà un valore errato social.technet.microsoft.com/wiki/contents/articles/…
Shanky
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.