Sql-Server

VMWare 記憶體大小調整和 SQL Server 2014

  • February 15, 2017

我們有一個生產伺服器,它每天多次轉儲它的頁面預期壽命(爬升到 2500 秒並回落到接近 0 秒)……在觀看了一些有關 SQL Server 虛擬化的培訓影片後,我被指向幾個 Perfmon 計數器來查看:

  • MB 記憶體限制
  • 記憶體膨脹(以 MB 為單位)
  • 以 MB 為單位的記憶體預留
  • 以 MB 為單位交換的記憶體

Ballooned、Reserved 和 Swapped 都為 0,但 Memory Limit 設置為接近 3tb(可能是預設設置,如 SQL 的 Max Memory 設置……)

我在 PLE 降至 0 且沒有任何計數器更改的事件期間查看了這些計數器。根據 Spotlight 的說法,緩衝區記憶體和過程記憶體的使用率仍然很高,除了 PLE 本身之外,似乎沒有任何統計數據真正讓步。

對我來說,這表明分配給機器的 RAM 不足,以至於許多查詢迫使伺服器查看磁碟以獲取結果。

我需要採取哪些步驟來證明或反駁這一點?

伺服器配置: - Windows 2008 r2 VM - 4 核 - 12GB RAM - 主數據庫約為 150GB

韋斯。這些 Perfmon 計數器是確保正確配置 VM 的良好開端(這意味著主機不會在 RAM 上過度使用。)

但是,它們無助於調整 VM 的大小。

如果您遇到性能問題,您需要確定兩件事:

  1. SQL Server 在此期間的最高等待時間,以及
  2. 導致等待的查詢

要獲得最高等待,請嘗試執行sp_BlitzFirst @SinceStartup =1。(免責聲明:這是一個開源腳本,我是作者之一。)您還可以使用第 3 方監控工具,如 Idera SQL DM、Quest Spotlight 和 SQL Sentry Performance Advisor。(免責聲明:那些要花錢,我沒有寫任何這些,但它們很棒。)

@SinceStartup = 1 開關讓您在啟動後等待,這不像監控軟體那麼酷,但它是免費啟動。

如果您的首要等待是 PAGEIOLATCH,這意味著從數據文件中讀取數據頁。如果是這種情況,您希望找到讀取最多數據的查詢。為此,請使用sp_BlitzCache @SortOrder = ‘reads’ (同樣,免責聲明,開源腳本,我是作者之一。)

這將為您提供按讀取的數據量排序的前 10 個查詢。它們通常是索引調整或查詢調整的候選者。我總是寧願調整這些而不是添加記憶體,但如果 PAGEIOLATCH 是您的首要等待,並且您不允許調整前 10 個查詢,也不允許調整它們的索引,那麼下一個解決方案是向 VM 添加記憶體。(但只有在走這條故障排除路線之後。)

您可以使用sys.dm_io_virtual_file_statsDMV 來擷取有關數據庫文件發生了多少 I/O 的詳細資訊。

由於對非日誌文件的所有 I/O 都與數據請求直接相關,這些請求被讀入緩衝池並在 DMV 中擷取,因此您可以看到在頁面生命週期內發生了多少 I/O預期下降。我使用以下程式碼在 1 分鐘內抽查 I/O 速率,但您可以根據需要調整時間段:

DECLARE @t TABLE 
(
   RunNum int NOT NULL
   , DBName sysname NOT NULL
   , DBFileName sysname NOT NULL
   , DBPhysicalFile varchar(260) NOT NULL
   , BytesRead bigint NOT NULL
   , BytesWritten bigint NOT NULL
   , Reads bigint NOT NULL
   , Writes bigint NOT NULL
   , SampleMs bigint NOT NULL
);

INSERT INTO @t 
SELECT 1
   , d.name
   , mf.name
   , mf.physical_name
   , vfs.num_of_bytes_read
   , vfs.num_of_bytes_written
   , vfs.num_of_reads
   , vfs.num_of_writes
   , vfs.sample_ms
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
   INNER JOIN sys.databases d ON vfs.database_id = d.database_id
   INNER JOIN sys.master_files mf ON vfs.database_id = mf.database_id
       AND vfs.file_id = mf.file_id
WHERE mf.type_desc = 'ROWS'
ORDER BY d.name
   , mf.name;

WAITFOR DELAY '00:01:00';  --switch this to whatever delay you like

INSERT INTO @t 
SELECT 2
   , d.name
   , mf.name
   , mf.physical_name
   , vfs.num_of_bytes_read
   , vfs.num_of_bytes_written
   , vfs.num_of_reads
   , vfs.num_of_writes
   , vfs.sample_ms
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
   INNER JOIN sys.databases d ON vfs.database_id = d.database_id
   INNER JOIN sys.master_files mf ON vfs.database_id = mf.database_id
       AND vfs.file_id = mf.file_id
WHERE mf.type_desc = 'ROWS'
ORDER BY d.name
   , mf.name;

--details by database and file
;WITH cte AS 
(
   SELECT t1.RunNum
       , t1.DBName
       , t1.DBFileName
       , t1.DBPhysicalFile
       , BytesRead = LEAD(t1.BytesRead, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.BytesRead
       , BytesWritten = LEAD(t1.BytesWritten, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.BytesWritten
       , Reads = LEAD(t1.Reads, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.Reads
       , Writes = LEAD(t1.Writes, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.Writes
   FROM @t t1
)
SELECT *
FROM cte
WHERE cte.RunNum = 1;

--summary
;WITH cte AS 
(
   SELECT t1.RunNum
       , t1.DBName
       , t1.DBFileName
       , t1.DBPhysicalFile
       , BytesRead = LEAD(t1.BytesRead, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.BytesRead
       , BytesWritten = LEAD(t1.BytesWritten, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.BytesWritten
       , Reads = LEAD(t1.Reads, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.Reads
       , Writes = LEAD(t1.Writes, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.Writes
       , MillisecondsDuration = LEAD(t1.SampleMs, 1, 0) 
           OVER (PARTITION BY t1.DBName, t1.DBFileName ORDER BY t1.RunNum) - t1.SampleMs
   FROM @t t1
)
SELECT TotalBytesRead = SUM(cte.BytesRead)
   , TotalBytesWritten = SUM(cte.BytesWritten)
   , TotalReads = SUM(cte.Reads)
   , TotalWrites = SUM(cte.Writes)
   , SampleSeconds = MAX(cte.MillisecondsDuration) / 1000
FROM cte
WHERE cte.RunNum = 1;

您可以使用第二個結果集中返回的匯總數字來查看有多少字節被讀入記憶體。如果該數字高於max server memory (mb),那麼您肯定需要更多記憶體以避免低 PLE 數字。

引用自:https://dba.stackexchange.com/questions/164452