Apa metode deterministik untuk mengevaluasi ukuran buffer pool yang masuk akal?

29

Saya mencoba mencari cara yang waras untuk memahami apakah max server memory (mb)pengaturannya sesuai (baik harus lebih rendah, atau lebih tinggi, atau tetap seperti itu). Saya sadar bahwa max server memory (mb)harus selalu cukup rendah untuk meninggalkan ruang untuk sistem operasi itu sendiri, dll.

Lingkungan yang saya cari memiliki beberapa ratus server; Saya membutuhkan formula yang andal yang dapat saya gunakan untuk menentukan apakah ukuran buffer pool saat ini tepat karena RAM dihitung biayanya per GB yang dialokasikan untuk setiap server. Seluruh lingkungan divirtualisasi, dan RAM "fisik" yang dialokasikan untuk VM dapat dengan mudah diubah ke atas atau ke bawah.

Saya punya SQL Server Instance tertentu yang saya lihat sekarang dengan PLE 1.100.052 detik, yang setara dengan 12.7 hari (jumlah waktu server telah naik). Server memiliki pengaturan memori server maks 2560MB (2.5GB), di mana hanya 1380MB (1.3GB) yang benar-benar dikomit.

Saya telah membaca beberapa item termasuk satu oleh Jonathan Keheyias ( post ) dan lainnya oleh Paul Randal ( post ), dan beberapa lainnya. Jonathan menganjurkan pemantauan untuk PLE di bawah 300 per 4GB dari buffer pool terlalu rendah. Untuk SQL Server Instance di atas, 300 * (2.5 / 4) = 187menghasilkan PLE target yang benar-benar sangat rendah di bawah 300. Contoh ini memiliki 290GB data SQL Server (tidak termasuk file log), dan hanya digunakan untuk pengujian integrasi. Dengan asumsi 12 hari terakhir mewakili penggunaan tipikal untuk server ini, saya akan mengatakan max server memory (mb)pengaturannya bisa diturunkan.

Di ujung lain skala, saya memiliki server uji integrasi dengan PLE 294, yang hanya memiliki max server memory (mb)pengaturan 1GB. Server ini hanya memiliki 224MB data SQL Server yang tidak termasuk log, dan menjalankan beberapa basis data BizFlow. Server ini mungkin mendapat manfaat dari max server memory (mb)pengaturan yang lebih tinggi .

Saya sedang memikirkan tempat awal yang baik untuk target yang mungkin ditugaskan terlalu banyak memori dapat mencakup melihat:

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;

Jika BufferPoolCommitTargetMB / BufferPoolCommittedMBlebih besar dari 1, server tidak menggunakan seluruh kumpulan buffer. Jika mesin tersebut juga memiliki PLE lebih besar dari "x" maka itu mungkin merupakan kandidat yang baik untuk penurunan max server memory (mb).

Karena Buffer Manager:Lazy writes/secpenghitung kinerja melacak berapa kali SQLOS telah menulis halaman ke disk antara pos-pos pemeriksaan karena tekanan memori, ini mungkin hal lain yang baik untuk dilihat.

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;

Kode di atas menganggap server berada di bawah beban selama 15 detik yang diperlukan untuk menjalankan, jika tidak maka akan melaporkan 0; yang mungkin salah-negatif menyesatkan.

Haruskah saya juga melihat PAGELATCHIO_*statistik tunggu atau jenis tunggu lain sebagai indikator tekanan memori, atau kekurangannya?

Pertanyaan saya adalah, bagaimana saya dapat andal menentukan nilai target "baik" untuk PLE dan max server memory (mb)?

Max Vernon
sumber

Jawaban:

11

Seperti yang sudah Anda ketahui tidak ada rumus umum untuk menghitung memori server maks. Anda dapat melakukan beberapa matematika cepat dan mencapai suatu nilai tetapi tetap saja Anda akan memerlukan bantuan penghitung Perfmon pada akhirnya untuk memantau penggunaan memori dan mengubahnya sesuai dengan itu. Saya tahu di bawah formula umum dan saya menggunakannya juga. Saya mempelajari formula ini dari Tautan Ini

Untuk SQL Server 2005 hingga 2008 R2

Harap dicatat dari SQL Server 2005 hingga 2008 R2 hanya memori server yang mengontrol kolam penyangga. Jadi konfigurasi memori server maks sedikit membosankan di sini dan melibatkan beberapa perhitungan

  1. Biarkan memori 2 G langsung untuk OS Windows.

  2. Tentu saja sistem akan menjalankan antivirus. Silakan tinggalkan 1.5G untuk Antivirus. Harap dicatat Mcafee dan SQL Server tidak berjalan seiring jadi pastikan Anda meninggalkan cukup untuk itu. Anda juga dapat memeriksa penghitung perfmon Perfmon Process-> Private bytes and Working Setuntuk memantau penggunaan memori oleh AV dan aplikasi kecil lainnya yang berjalan pada kotak SQL Server

masukkan deskripsi gambar di sini

  1. Pertimbangkan persyaratan memori driver / firmware. Anda harus menurunkannya berdasarkan persyaratan memori oleh driver yang diinstal pada sistem. Alat RAMMAP dapat membantu

  2. Pertimbangkan persyaratan memori NonbPool (alias MTL atau MTR) oleh SQL Server.

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

    + Utas pekerja maks * 2MB

    + Memori untuk alokasi Windows langsung sekitar 0 hingga 300 MB dalam sebagian besar kasus, tetapi Anda mungkin harus meningkatkannya jika ada banyak komponen pihak ketiga yang dimuat dalam proses SQL Server (Termasuk server yang ditautkan, dll. Pencadangan pihak ketiga, dll.)

    + Jika Anda menggunakan CLR secara ekstensif tambahkan beberapa memori tambahan untuk CLR.

  3. Pertimbangkan persyaratan memori berdasarkan pekerjaan (Termasuk agen replikasi, pengiriman Log, dll.) Dan paket yang akan berjalan di server. Itu bisa sangat dari MB ke GB sesuai dengan jumlah pekerjaan yang berjalan. Untuk server berukuran sedang Anda dapat menganggapnya sebagai 250 MB

  4. Pastikan ada ruang kosong yang cukup baik untuk sistem operasi.

    Kira-kira (100 MB untuk setiap GB hingga 4G) + (50 MB untuk setiap GB tambahan hingga 12GB) + (25 MB untuk setiap GB tambahan hingga ukuran RAM Anda)

  5. Persyaratan memori lainnya.

    Jika Anda memiliki persyaratan memori lain khusus untuk lingkungan Anda.

    Memori server maks = Total memori fisik - (1 + 2 + 3 + 4 + 5 + 6 + 7)

    Saya belum menyertakan konfigurasi memori untuk SSIS.SSRS, SSAS Anda juga perlu mengurangi memori yang diperlukan oleh layanan ini dari total memori server fisik.

    Setelah mengkonfigurasi di atas, Anda perlu memantau penghitung berikut

  • SQLServer: Buffer Manager - Page Life Expectancy (PLE):

  • SQLServer: Buffer Manager - CheckpointPages / dtk:

  • SQLServer: Memory Manager - Memory Grants Tertunda:

  • SQLServer: memory Manager - Memory Server Target:

  • SQLServer: memory Manager - Total Server memory

Untuk SQL Server 2012/2014.

From SQL Server 2012 onwardspengaturan memori server maks menjadi mudah. Karena sekarang memori server maks hampir mencakup semua konsumsi memori. Memori server maksimum mengontrol alokasi memori Server SQL, termasuk kumpulan buffer, kompilasi memori, semua cache, hibah memori qe, memori manajer kunci, dan memori CLR (pada dasarnya setiap "pegawai" seperti yang ditemukan di dm_os_memory_clerks). Memori untuk tumpukan thread, tumpukan, penyedia server tertaut selain SQL Server, atau memori apa pun yang dialokasikan oleh DLL "non SQL Server" tidak dikendalikan oleh memori server maks.

Anda dapat mengalokasikan 75-80% untuk SQL Server dan kemudian menggunakan penghitung perfmon untuk memantau penggunaan memori. Dalam SQL Server 2012 beberapa penghitung perfmon telah ditinggalkan. Penghitung manajer penyangga sudah usang Anda harus menggunakan penghitung manajer memori

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

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

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

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

Pada nilai PLE, saya telah menggunakan formula oleh Joanthan dan untungnya itu berhasil bagi saya.

Shanky
sumber
6

Tantangannya di sini adalah bahwa angka tidak memperhitungkan pengalaman pengguna akhir akun.

Contoh yang bagus: Saya memiliki server database yang digunakan untuk melacak setiap situs web yang dikunjungi karyawan perusahaan. Saya tidak peduli apakah itu tidak bisa mengikuti sisipan selama beban puncak karena aplikasi ujung depan mengumpulkan sisipan secara berkala, dan sisipan lambat tidak menyebabkan masalah bagi pengguna. Pengguna masih dapat menjelajahi web tanpa ditahan oleh sisipan lambat.

Pada waktu SELECT, departemen SDM hanya memadamkan laporan ketika ditanya tentang riwayat perambanan yang mencurigakan untuk karyawan tertentu, tetapi mereka tidak peduli berapa lama waktu yang dibutuhkan untuk laporan - mereka hanya membuka laporan dan pergi untuk melakukan hal-hal lain.

Kinerja perlu dimulai dengan pertanyaan: apakah pengguna senang dengan kinerja? Jika demikian, tinggalkan sistem di tempatnya.

Brent Ozar
sumber
Bahkan jika Anda menggunakan lebih banyak memori daripada yang Anda perlukan?
James Anderson
2
James - secara umum, saya tidak ingin membuat perubahan yang menyebabkan pengguna mengeluh. Jika Anda ingin melakukan itu, Anda dapat secara bertahap mengecilkan jumlah memori untuk setiap server sampai pengguna mulai mengeluh, tetapi ketika saya sudah terlalu banyak bekerja, saya biasanya tidak punya waktu untuk mengambil langkah-langkah itu. Saya harus fokus pada tugas-tugas yang akan membuat pengguna yang tidak bahagia bahagia - daripada mencoba membuat pengguna yang bahagia tidak bahagia. ;-)
Brent Ozar
2
Poin bagus, Brent. Saya diminta untuk melihat apakah beberapa server kelebihan ketentuan karena kami membayar memori per GB per tahun. Banyak contoh yang saya lihat memiliki apa yang saya anggap sebagai jumlah RAM yang sangat kecil max server memory (mb), dan karena itu saya cukup enggan untuk menurunkan ukurannya. Namun, beberapa contoh lain memiliki 1.000.000 + PLE, dan dengan demikian adalah kandidat potensial yang cukup jelas untuk penurunan RAM. Jelas, menurunkan RAM akan menyebabkan peningkatan IOPS, dan aku tidak yakin apa biaya yang akan.
Max Vernon
1
Juga, melihat PLE dibandingkan dengan max server memorypengaturan adalah semacam hal ayam dan telur; semakin rendah max server memorypengaturan, semakin rendah minimum "dapat diterima" PLE akan, jadi saya bisa terjebak dalam spiral yang semakin rendah. Saya yakin, seperti yang Anda sebutkan, kinerja pengguna pada suatu saat akan terpengaruh.
Max Vernon
Penghitung PLE adalah salah satu yang harus Anda hindari sejak tahun 2012 dan seterusnya atau ketika Anda memiliki sistem NUMA di mana setiap node berperilaku sebagai pengalokasi memori kecil sendiri. Jika mau, Anda harus mencari PLE untuk setiap NUMA node yang tidak lengkap Anda mungkin mendapatkan nilai yang salah
Shanky
3

T-SQL saat ini yang saya gunakan untuk mengevaluasi PLE vs max server memoryadalah:

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

Kode ini membandingkan PLE dengan PLE minimum "yang dapat diterima" untuk jumlah max server memorysistem yang telah dikonfigurasi. Jika PLE jauh lebih tinggi dari angka yang dapat diterima, ini menunjukkan maksimum 10% lebih rendah max server memory. Jika PLE lebih rendah dari PLE yang dapat diterima, itu menunjukkan maksimum 10% lebih max server memory.

Jika jumlah aktual buffer pool yang dikomit kurang dari ukuran pool buffer target, disarankan menurunkan max server memoryjumlah itu, ditambah beberapa memori tambahan untuk utas, tulis malas, dll.

Kode ini juga melihat berbagai penghitung kinerja untuk hal-hal seperti Lazy Writes / second, Free List Stalls, dan Batch Requests.

Kode tidak sempurna, saya membagikannya di sini untuk mendapatkan masukan, dan untuk kepentingan pengguna SO di masa mendatang.

Max Vernon
sumber
1
Max Pikiran Anda mulai dari target SQL Server 2012 Buffer Pool dan berkomitmen tidak masuk akal dan penghitung ini sudah usang. Sebaliknya Anda harus menggunakan Memory Manager Target Committed (KB) dan komitmen saat ini. Jika Anda ingin membaca lebih lanjut mengapa hal itu memberikan nilai yang salah social.technet.microsoft.com/wiki/contents/articles/...
Shanky