합리적인 버퍼 풀 크기를 평가하는 결정적인 방법은 무엇입니까?


29

max server memory (mb)설정이 적절한 지 (낮거나 더 높아야하거나 그대로 유지해야 함) 를 이해하는 건전한 방법을 고안하려고합니다 . max server memory (mb)운영 체제 자체를위한 공간을 확보 할 수있을만큼 항상 낮아야 한다는 것을 알고 있습니다.

내가보고있는 환경에는 수백 대의 서버가 있습니다. RAM이 각 서버에 할당 된 GB 당 비용이 들기 때문에 버퍼 풀의 현재 크기가 적절한 지 여부를 결정하는 데 사용할 수있는 안정적인 공식이 필요합니다. 전체 환경이 가상화되며 VM에 할당 된 "실제"RAM을 쉽게 위 또는 아래로 변경할 수 있습니다.

필자가 지금보고있는 특정 SQL Server 인스턴스가 1,100,052 초이며 12.7 일 (서버가 가동 된 시간)에 해당합니다. 서버의 최대 서버 메모리 설정은 2560MB (2.5GB)이며 그 중 1380MB (1.3GB) 만 실제로 커밋됩니다.

Jonathan Keheyias ( post )와 Paul Randal ( post ), 여러 항목을 포함한 여러 항목을 읽었 습니다. Jonathan 은 4GB 버퍼 풀당 300 미만의 PLE 모니터링 이 너무 낮다고 주장 합니다. 위의 SQL Server 인스턴스의 300 * (2.5 / 4) = 187경우 실제로 300 미만의 대상 PLE가 낮습니다.이 인스턴스는 290GB의 SQL Server 데이터 (로그 파일 제외)를 가지며 통합 테스트에만 사용됩니다. 지난 12 일이이 서버의 일반적인 사용을 대표한다고 가정하면 max server memory (mb)설정 낮출 수 있다고 합니다.

규모의 다른 쪽 끝에는 max server memory (mb)1GB 로 설정된 PLE이 294 인 또 다른 통합 테스트 서버가 있습니다. 이 서버에는 로그를 포함하지 않는 224MB의 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 / BufferPoolCommittedMB1보다 큰 경우, 서버는 전체 버퍼 풀을 사용하지 않는다. 해당 기계의 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. Windows OS 용으로 2G 메모리를 바로 두십시오.

  2. 물론 시스템에는 바이러스 백신이 실행됩니다. 바이러스 백신을 위해 1.5G를 남겨 두십시오. Mcafee와 SQL Server는 서로 밀접한 관계가 없으므로 충분히 남겨 두십시오. 또한 perfmon 카운터 Perfmon Process-> Private bytes and Working Set를 확인 하여 SQL Server 상자에서 실행되는 AV 및 기타 소규모 응용 프로그램의 메모리 사용량을 모니터링 할 수 있습니다

여기에 이미지 설명을 입력하십시오

  1. 드라이버 / 펌웨어의 메모리 요구 사항을 고려하십시오. 시스템에 설치된 드라이버의 메모리 요구 사항을 기반으로이를 도출해야합니다. RAMMAP 도구가 도움이 될 수 있습니다

  2. SQL Server의 NonbPool (일명 MTL 또는 MTR) 메모리 요구 사항을 고려하십시오.

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

    + 최대 작업자 스레드 * 2MB

    + 대부분의 경우 약 0-300MB의 직접 Windows 할당을위한 메모리이지만 SQL Server 프로세스에로드 된 많은 타사 구성 요소가있는 경우이를 증가시켜야 할 수도 있습니다 (링크 된 서버 dll, 타사 백업 dll 등 포함).

    + CLR을 광범위하게 사용하는 경우 CLR에 추가 메모리를 추가하십시오.

  3. 작업 (복제 에이전트, 로그 전달 등 포함) 및 서버에서 실행될 패키지의 메모리 요구 사항을 고려하십시오. 실행중인 작업 수에 따라 MB에서 GB로 매우 다양 할 수 있습니다. 중간 크기 서버의 경우 250MB로 사용할 수 있습니다

  4. 운영 체제를위한 충분한 여유 공간이 있는지 확인하십시오.

    약 (GB 당 4GB에서 100GB까지) + (GB 당 12GB에서 50GB까지) + (RAM 크기까지 추가 GB 당 25MB)

  5. 다른 메모리 요구 사항

    환경과 관련된 다른 메모리 요구 사항이있는 경우

    최대 서버 메모리 = 총 실제 메모리 – (1 + 2 + 3 + 4 + 5 + 6 + 7)

    SSIS.SSRS, SSAS에 대한 메모리 구성을 포함하지 않았으므로 전체 물리적 서버 메모리에서 이러한 서비스에 필요한 메모리를 빼야합니다.

    위에서 구성한 후 다음 카운터를 모니터링해야합니다.

  • SQLServer : 버퍼 관리자-페이지 수명 (PLE) :

  • SQLServer : 버퍼 관리자 --CheckpointPages / sec :

  • SQLServer : 메모리 관리자-메모리 부여 보류 :

  • SQLServer : 메모리 관리자-대상 서버 메모리 :

  • SQLServer : 메모리 관리자-총 서버 메모리

SQL Server 2012/2014의 경우

From SQL Server 2012 onwards최대 서버 메모리 설정이 쉬워졌습니다. max server memory는 거의 모든 메모리 소비를 설명하기 때문입니다. Max 서버 메모리는 버퍼 풀, 컴파일 메모리, 모든 캐시, qe 메모리 부여, 잠금 관리자 메모리 및 CLR 메모리 (기본적으로 dm_os_memory_clerks에있는“클라크”)를 포함하여 SQL Server 메모리 할당을 제어합니다. 스레드 스택, 힙, SQL Server 이외의 연결된 서버 공급자 또는 "비 SQL Server"DLL에 의해 할당 된 메모리에 대한 메모리는 max server memory에 의해 제어되지 않습니다.

SQL Server에 75-80 %를 할당 한 다음 perfmon 카운터를 사용하여 메모리 사용을 모니터링 할 수 있습니다. SQL Server 2012에서는 일부 perfmon 카운터가 더 이상 사용되지 않습니다. 버퍼 관리자 카운터는 더 이상 사용되지 않으며 메모리 관리자 카운터를 사용해야합니다.

  • SQL Server : 메모리 관리자-대상 서버 메모리 (KB)

  • SQL Server : 메모리 관리자-총 서버 메모리 (KB)

  • SQL Server : 메모리 관리자-사용 가능한 메모리 (KB)

  • SQL Server : 메모리 관리자-데이터베이스 캐시 메모리 (KB)

PLE의 가치에 따라 Joanthan의 수식을 사용했으며 다행히도 그것은 나를 위해 일했습니다.


6

여기서 문제는 숫자가 최종 사용자 경험을 고려하지 않는다는 것입니다.

좋은 예 : 회사 직원이 방문하는 모든 웹 사이트를 추적하는 데 사용되는 데이터베이스 서버가 있습니다. 프론트 엔드 앱이 인서트를 주기적으로 배치하고 느린 인서트는 사용자에게 문제를 일으키지 않기 때문에 피크로드 동안 인서트를 유지할 수 없는지 걱정하지 않습니다. 사용자는 느린 삽입물에 얽매이지 않고 웹을 서핑 할 수 있습니다.

SELECT 부서에서 HR 부서는 특정 직원에 대한 의심스러운 탐색 기록을 요청하면 보고서를 시작하지만 보고서가 얼마나 오래 걸리는지 신경 쓰지 않습니다. 보고서를 열고 다른 일을하기 만합니다.

성능은 질문으로 시작해야합니다. 사용자는 성능에 만족합니까? 그렇다면 시스템을 그대로 두십시오.


필요한 것보다 더 많은 메모리를 사용하더라도?
James Anderson

2
James-일반적으로 사용자가 불만을 일으키는 변경을하고 싶지 않습니다. 그렇게하려면 사용자가 불만을 제기 할 때까지 각 서버의 메모리 양을 점차적으로 줄이십시오. 그러나 이미 과로 한 경우에는 일반적으로 이러한 단계를 수행 할 시간이 없습니다. 나는 행복한 사용자를 불행하게 만드는 대신 불행한 사용자를 행복하게하는 작업에 집중해야합니다. ;-)
Brent Ozar

2
좋은 지적이야, 브렌트 매년 GB 당 메모리 요금을 지불하기 때문에 일부 서버가 초과 프로비저닝되었는지 확인하라는 요청을 받았습니다. 내가보고있는 많은 인스턴스는에 매우 적은 양의 RAM으로 간주되는 것을 가지고 있으므로 max server memory (mb)크기를 줄이는 것을 꺼려합니다. 그러나 일부 다른 인스턴스에는 1,000,000 + PLE가 있으므로 RAM이 떨어질 가능성이 매우 높습니다. 분명, RAM을 낮추는 것은 IOPS의 증가의 원인이되고, 나는 확실히 비용 어떤 아니에요 것이다.
Max Vernon

1
또한 max server memory설정에 비해 PLE를 보는 것은 일종의 닭고기와 달걀입니다. 는 낮은 max server memory내가 지금까지 낮추는 나선형에 붙어 얻을 수 있도록, 최소는 "허용"PLE가 될 것이다 낮은, 설정을. 언급했듯이 사용자 성능이 어느 시점 에 영향 을 줄 것이라고 확신 합니다.
Max Vernon

PLE 카운터는 2012 년 이후 또는 각 노드가 자체 소형 메모리 할당 자로 동작하는 NUMA 시스템이있을 때 피해야하는 카운터입니다. 완료하지 않은 각 NUMA 노드에 대해 PLE을 찾아야한다면 잘못된 값을 얻을 수 있습니다.
Shanky

3

PLE을 평가하는 데 사용하는 현재 T-SQL 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을 max server memory시스템이 구성한 양에 대한 최소 "허용 가능한"PLE와 비교합니다 . PLE가 허용 가능한 숫자보다 상당히 높으면 최대 10 % 더 낮습니다 max server memory. PLE가 허용 가능한 PLE보다 낮 으면 최대 10 % 더 max server memory좋습니다.

커밋 된 버퍼 풀의 실제 크기가 대상 버퍼 풀 크기보다 작은 경우 해당 크기로 낮추고 max server memory스레드, 지연 쓰기 등에 대한 추가 메모리를 제안합니다 .

이 코드는 또한 Lazy Writes / second, Free List Stalls 및 Batch Requests와 같은 다양한 성능 카운터를 살펴 봅니다.

코드는 완벽하지 않으며 입력을 받기 위해 여기에서 공유하고 향후 SO 사용자의 이익을 위해 공유하고 있습니다.


1
SQL Server 2012 버퍼 풀 대상에서 시작하여 커밋 된 Max Mind는 의미가 없으며 이러한 카운터는 더 이상 사용되지 않습니다. 대신 메모리 관리자 대상 커밋 (KB) 및 현재 커밋을 사용해야합니다. 왜 가치가 잘못되었는지 더 자세히 알고 싶다면 social.technet.microsoft.com/wiki/contents/articles/…
Shanky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.