Що таке детермінований метод оцінки розміру чутливого буфера?


29

Я намагаюся придумати розумний спосіб зрозуміти, чи max server memory (mb)налаштування підходить (або повинно бути нижче, або вище, або залишитися таким, яким воно є). Я усвідомлюю, що max server memory (mb)завжди має бути досить низько, щоб залишати місце для самої операційної системи тощо.

Середовище, на яке я дивлюсь, має кілька сотень серверів; Мені потрібна достовірна формула, яку я можу використовувати, щоб визначити, чи відповідає теперішній розмір буферного пулу, оскільки оперативна пам'ять коштує за ГБ, що виділяється на кожен сервер. Все середовище віртуалізоване, і "фізичну" оперативну пам'ять, виділену для VM, можна легко змінити вгору або вниз.

У мене є конкретний екземпляр SQL Server, на який я зараз дивлюся, PLE складає 1,100 052 секунди, що дорівнює 12,7 дням (кількість часу, коли сервер працював). На сервері встановлено максимальну пам'ять сервера - 2560 МБ (2,5 ГБ), з яких фактично лише 1380 МБ (1,3 ГБ).

Я прочитав декілька предметів, серед яких один Джонатан Кехейя ( пост ) та інший Пол Рандал ( пост ) та кілька інших. Джонатан виступає за моніторинг для PLE нижче 300 на 4 ГБ буферного пулу як занадто низького. Для вищевказаного екземпляра SQL Server 300 * (2.5 / 4) = 187результат дійсно низького цільового значення PLE нижче 300. Цей екземпляр має 290 ГБ даних SQL Server (не включаючи файли журналів) і використовується лише для тестування інтеграції. Якщо припустити, що останні 12 днів є типовим для цього сервера, я б сказав, що max server memory (mb)налаштування можна знизити.

На іншому кінці шкали, у мене є ще один тестовий сервер інтеграції з PLE 294, у якого max server memory (mb)встановлено лише 1 Гб. Цей сервер має лише 224 Мб даних SQL Server, не включаючи журнали, і працює з деякими базами даних BizFlow. Цей сервер може отримати перевагу від більш високих max server memory (mb)параметрів.

Я думаю, що гарне місце для цілей, яким може бути призначено занадто багато пам'яті, може включати перегляд:

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;

Якщо BufferPoolCommitTargetMB / BufferPoolCommittedMBбільший за 1, сервер не використовує весь пул буфера. Якщо машина, про яку йдеться, також має значення PLE, що перевищує "x", це може бути хорошим кандидатом на зменшення max server memory (mb).

Оскільки Buffer Manager:Lazy writes/secлічильник продуктивності відстежує кількість разів, коли SQLOS писав сторінки на диск між контрольними точками через тиск в пам'яті, це може бути ще однією хорошою справою.

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;

Вищенаведений код передбачає, що сервер перебуває під навантаженням протягом 15 секунд, які потрібно запустити, інакше він повідомить про 0; що може бути помилковим помилковим негативом.

Чи слід також розглядати PAGELATCHIO_*статистику очікування чи якийсь інший тип очікування як індикатор тиску пам'яті або його відсутність?

Моє запитання полягає в тому, як я можу надійно визначити "хороше" цільове значення для PLE і max server memory (mb)?

Відповіді:


11

Як ви вже знаєте, немає загальної формули для обчислення максимальної пам’яті сервера, ви можете зробити кілька швидких математичних значень і досягти значення, але все-таки вам знадобиться допомога лічильників Perfmon нарешті для моніторингу використання пам’яті та відповідних змін. Я знаю нижче загальну формулу, і я її також використовую. Я дізнався цю формулу з цього посилання

Для SQL Server 2005–2008 R2

Зверніть увагу, що від SQL Server 2005 до 2008 р. Максимальна пам'ять сервера R2 управляє лише буферним пулом. Тож конфігурація максимальної пам’яті сервера тут трохи стомлююча і включає кілька розрахунків

  1. Залиште 2 Г пам'яті відразу для ОС Windows.

  2. Звичайно, система матиме антивірусний запуск. Залиште 1,5G для антивірусу. Зверніть увагу, що Mcafee і SQL Server не йдуть рука об руку, тому переконайтесь, що ви залишите достатньо для цього. Ви також можете перевірити лічильник парфмонів Perfmon Process-> Private bytes and Working Setдля моніторингу використання пам'яті AV та інших невеликих додатків, що працюють на вікні SQL Server

введіть тут опис зображення

  1. Розглянемо вимоги до пам'яті драйверів / прошивки. Виводити її потрібно, виходячи з вимог пам'яті драйверів, встановлених у системі. Засіб RAMMAP може допомогти

  2. Розглянемо вимоги пам'яті NonbPool (він же MTL або MTR) на SQL Server.

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

    + Макс робочих ниток * 2 Мб

    + Пам'ять для прямих виділень Windows у більшості випадків приблизно від 0 до 300 Мб, але, можливо, доведеться збільшити її, якщо в процесі роботи на SQL Server завантажено багато компонентів 3-х сторін (включаючи пов'язані DLL-сервери, резервні копії DLL-пакетів тощо).

    + Якщо ви широко використовуєте CLR, додайте додаткову пам'ять для CLR.

  3. Розгляньте вимогу пам'яті за завданнями (включаючи агенти реплікації, доставку журналу тощо) та пакетами, які працюватимуть на сервері. Відповідно до кількості виконаних завдань, це може бути від MB до GB. Для сервера середнього розміру ви можете взяти його як 250 МБ

  4. Переконайтеся, що є достатньо хорошого вільного місця для операційної системи.

    Приблизно (100 МБ на кожен ГБ до 4 Г) + (50 МБ на кожен додатковий ГБ до 12 ГБ) + (25 МБ на кожен додатковий ГБ до розміру ОЗУ)

  5. Інші вимоги до пам'яті.

    Якщо у вас є якісь інші вимоги до пам'яті, характерні для вашого оточення.

    Максимальна пам'ять сервера = Загальна фізична пам'ять - (1 + 2 + 3 + 4 + 5 + 6 + 7)

    Я не включив конфігурацію пам'яті для SSIS.SSRS, SSAS, вам також потрібно було б відняти необхідну для цих служб пам'ять із загальної фізичної пам'яті сервера.

    Після налаштування вище потрібно стежити за наступними лічильниками

  • SQLServer: Buffer Manager - тривалість життя сторінки (PLE):

  • SQLServer: Buffer Manager - CheckpointPages / sec:

  • SQLServer: Менеджер пам'яті - Грант пам'яті:

  • SQLServer: Менеджер пам'яті - Цільова пам'ять сервера:

  • SQLServer: Менеджер пам'яті - Загальна пам'ять сервера

Для SQL Server 2012/2014.

From SQL Server 2012 onwardsналаштування максимальної пам’яті сервера стало легко. Тому що зараз максимальна пам'ять сервера майже припадає на все споживання пам'яті. Макс серверної пам’яті керує розподілом пам’яті SQL Server, включаючи пул буфера, компіляцію пам’яті, усі кеші, гранти qe, пам’ять менеджера блокування та пам’ять CLR (в основному будь-який «клерк», як знайдено в dm_os_memory_clerks). Пам'ять для потокових стеків, купи, пов'язаних постачальників серверів, відмінних від SQL Server, або будь-якої пам'яті, виділеної DLL "не SQL Server", не контролюється максимальною пам'яттю сервера.

Ви можете виділити 75-80% на SQL Server, а потім використовувати лічильники парфмонів для моніторингу використання пам'яті. У SQL Server 2012 застарілі лічильники парфмонів. Лічильник менеджера буфера застарілий, ви повинні використовувати лічильник менеджера пам'яті

  • SQL Server: Менеджер пам'яті-- Цільова пам'ять сервера (КБ)

  • SQL Server: Менеджер пам'яті - Загальна пам'ять сервера (КБ)

  • SQL Server: Менеджер пам'яті - Без пам'яті (КБ)

  • SQL Server: Менеджер пам'яті - Пам'ять кешу бази даних (КБ)

Щодо значення PLE, я використав формулу Джоантана і, на щастя, вона спрацювала для мене.


6

Проблема тут полягає в тому, що номери не враховують досвід кінцевих користувачів.

Чудовий приклад: у мене є сервер баз даних, який використовується для відстеження кожного веб-сайту, який відвідують співробітники компанії. Мені все одно, якщо він не може йти в ногу зі вставками під час пікових навантажень, оскільки передній додаток періодично вимикає вставки, а повільні вставки не створюють проблем для користувачів. Користувачі все ще можуть користуватися Інтернетом, не затримуючись повільними вставками.

У SELECT час відділ кадрів просто знімає звіти, коли їх запитують про підозрілу історію перегляду для того чи іншого співробітника, але їм все одно, скільки часу триватимуть звіти - вони просто відкривають звіт і починають робити інші речі.

Продуктивність повинна починатися з питання: чи задоволені користувачі ефективністю? Якщо так, залиште систему там, де вона є.


Навіть якщо ви використовуєте більше пам'яті, ніж потрібно?
Джеймс Андерсон

2
Джеймс - взагалі кажучи, я не хочу вносити зміни, які викликають скарги користувачів. Якщо ви цього хочете, ви можете поступово зменшити об'єм пам'яті для кожного сервера, поки користувачі не почнуть скаржитися, але коли я вже перевантажений, я, як правило, не встигаю вжити цих кроків. Я маю зосередитись на завданнях, які роблять нещасних користувачів щасливими, а не намагаються зробити щасливих користувачів нещасними. ;-)
Брент Озар

2
Хороші бали, Брент. Мене попросили перевірити, чи є деякі сервери надмірно передбачені, оскільки ми платимо за пам'ять за ГБ на рік. У багатьох випадках, на які я дивлюся, є те, що я вважаю дуже невеликою кількістю оперативної пам’яті max server memory (mb), і, як такий, я дуже не хочу їх зменшувати. Однак деякі інші випадки мають 1 000 000 + PLE, і як такі є досить очевидними потенційними кандидатами на падіння оперативної пам'яті. Зрозуміло, що зниження оперативної пам’яті призведе до збільшення IOps, і я не впевнений, яка вартість цього буде.
Макс Вернон

1
Крім того, дивлячись на PLE порівняно з max server memoryналаштуванням, це вид курячого яйця; чим нижча max server memoryнастройка, тим нижчим буде мінімально "прийнятний" PLE, щоб я міг застрягти у спіралі, що постійно спадає. Я впевнений, що, як ви вже згадували, на деякий момент ефективність користувача вплине.
Макс Вернон

Лічильники PLE - це той, якому вам слід уникати перегляду з 2012 року або коли у вас система NUMA, де кожен вузол веде себе як власний невеликий розподільник пам'яті. Якщо ви хочете, вам слід шукати PLE для кожного вузла NUMA, який не завершений, ви можете отримати неправильне значення
Shanky

3

Поточний T-SQL, який я використовую для оцінки 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

Цей код порівнює PLE з мінімальним "прийнятним" PLE для кількості max server memoryналаштованої системи. Якщо показник PLE помітно вище прийнятного числа, він пропонує максимум на 10% нижче max server memory. Якщо PLE нижчий від прийнятного PLE, він пропонує максимум на 10% більше max server memory.

Якщо фактичний обсяг зафіксованого пулового буфера менший за розмір пулу цільового буфера, то це дозволяє зменшити max server memoryдо цієї кількості, плюс додаткову пам'ять для потоків, ліниві записи тощо.

Код також розглядає різні лічильники продуктивності для таких речей, як «Ледачі записи / секунди», «Безкоштовні списки списку» та «Пакетні запити».

Код не є ідеальним, я ділюсь ним тут, щоб отримати інформацію та на користь майбутніх користувачів ПП.


1
Max Mind ви починаєте з цілі буферного пулу SQL Server 2012 і виконуються без сенсу, і ці лічильники застарілі. Натомість ви повинні використовувати Менеджер пам’яті з цільовими зобов’язаннями (КБ) та поточним зобов'язанням. Якщо ви хочете прочитати більше, чому він дає неправильне значення social.technet.microsoft.com/wiki/contents/articles/…
Shanky
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.