無法在 In-Memory OLTP 中回收索引未使用的記憶體
重現問題的步驟
創建具有記憶體優化文件組和容器的數據庫 使用非集群 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/