Sql-Server

無法在 In-Memory OLTP 中回收索引未使用的記憶體

  • September 17, 2020

重現問題的步驟

創建具有記憶體優化文件組和容器的數據庫 使用非集群 pk 創建僅模式記憶體表 模擬插入和刪除活動。我的結果是我有高索引未使用的記憶體不會下降。

USE master
go
DROP DATABASE IF EXISTS MemoryOptimizedTest
CREATE DATABASE MemoryOptimizedTest
GO
USE MemoryOptimizedTest
GO
ALTER DATABASE MemoryOptimizedTest 
ADD FILEGROUP imoltp_mod CONTAINS MEMORY_OPTIMIZED_DATA
GO 

ALTER DATABASE MemoryOptimizedTest ADD FILE (name='imoltp_mod1', filename='c:\imoltp_mod1') TO FILEGROUP imoltp_mod
GO


DROP TABLE IF EXISTS dbo.MyCache
CREATE TABLE dbo.MyCache
(
   PK int NOT NULL, 
   SecondInt int NOT NULL,
   ThirdInt int NOT NULL,
    CONSTRAINT PK_MyCache PRIMARY KEY NONCLUSTERED (PK)
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)

go

/* Generate activity and monitor table size */
USE MemoryOptimizedTest
go


SELECT
   object_id,
   OBJECT_SCHEMA_NAME(object_id) + '.' + OBJECT_NAME(object_id) AS Table_Name,
   memory_allocated_for_table_kb,
   memory_used_by_table_kb,
   memory_allocated_for_indexes_kb,
   memory_used_by_indexes_kb
FROM sys.dm_db_xtp_table_memory_stats
WHERE OBJECT_ID = OBJECT_ID('dbo.MyCache')

;WITH
 L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
 L1   AS(SELECT 1 AS c FROM L0 CROSS JOIN L0 AS B),
 L2   AS(SELECT 1 AS c FROM L1 CROSS JOIN L1 AS B),
 L3   AS(SELECT 1 AS c FROM L2 CROSS JOIN L2 AS B),
 L4   AS(SELECT 1 AS c FROM L3 CROSS JOIN L3 AS B),
 L5   AS(SELECT 1 AS c FROM L4 CROSS JOIN L4 AS B),
 Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
, tally AS (SELECT TOP (10000) n FROM Nums ORDER BY n)
INSERT INTO dbo.MyCache (PK, SecondInt, ThirdInt)
SELECT 
   n
   , n+1
   , n+2
FROM tally 

WAITFOR DELAY '00:00:02'
DELETE FROM dbo.MyCache

GO 50

當我在本地機器 Microsoft SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64) Developer Edition 上執行它時,最大記憶體為 16 GB,可用記憶體為 1.5 GB,memory_allocated_for_indexes_kb 波動正常。

當我在我們的 DEV 環境中執行它時 Microsoft SQL Server 2019 (RTM-CU7) (KB4570012) - 15.0.4063.15 (X64) Enterprise edition 2 TB Max Memory, 220 GB 可用記憶體

memory_allocated_for_indexes_kb 只會增長。我已經為一個表模擬了幾個小時的活動,並且索引已用記憶體 = 0.24 MB,索引未使用記憶體 = 385 MB,它不會下降。

垃圾收集器根據 XTP 垃圾收集中的 PerfMon Sweep expired rows removed/sec 執行。

我在某處讀到垃圾收集器在面臨記憶體壓力之前不會釋放空間,但它會容納這麼多未使用的記憶體似乎很奇怪。

編輯:我將資源池用於保存記憶體表的數據庫。百分之一是我能做到的最低點。我用另一個佔資源池的 99% 的表填充了記憶體,並且 memory_allocated_for_indexes 仍然不會下降。是否有交易活動。沒有活動的事務阻止 GC,我已經等了 30 多分鐘。

我不能接受任何目前的答案,因為我的問題仍未得到解答。請注意,表行已被清理,但不是針對索引。

我在某處讀到垃圾收集器在面臨記憶體壓力之前不會釋放空間,但它會容納這麼多未使用的記憶體似乎很奇怪。

不過,這很奇怪嗎?為什麼現在垃圾收集可以推遲到以後:)

文件中,確認您的想法(強調我的):

使用者事務送出後,它會辨識與其執行的調度程序關聯的所有排隊項目,然後釋放記憶體。如果調度器上的垃圾回收隊列為空,它會搜尋目前 NUMA 節點中的任何非空隊列。如果事務活動低並且存在記憶體壓力,則主垃圾收集執行緒可以訪問任何隊列中的垃圾收集行。如果在(例如)刪除大量行之後沒有事務活動並且沒有記憶體壓力,則刪除的行不會被垃圾收集,直到事務活動恢復或存在記憶體壓力。

您的測試工作量似乎很小,如果它不足以觸發任何收集,我不會感到驚訝,尤其是系統的記憶體資源有多強大。

有了 2TB 的記憶體,我不會為此使用 < 500MB 的記憶體,也不會擔心這個,直到它成為一個實際的問題

您正在執行 Enterprise,因此您應該創建一個資源池,以便緩衝池不受記憶體增長的影響。

詳情在這裡:

http://nedotter.com/archive/2016/12/monitoring-in-memory-oltp-resource-pools/

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