当我在 SQL Server 中使用大对象 (LOB) 数据类型的变量时,整个内容是否始终保存在内存中?即使它是2GB的大小?
链接: https ://codingsight.com/understanding-the-importance-of-memory-setting-in-sql-server/
现在让我们简要地看一下调整内存大小的技术。
为操作系统保留 1 GB 内存 在初始 4 GB 之后,每 4 GB RAM 各 1 GB,最多 16 GB RAM 超过 16 GB 的 RAM 每 8 GB 1 GB 例如,如果您有一个32 GB RAM 数据库服务器,然后分配给操作系统的内存为
1 GB,最小分配
- 3 GB,因为 16 GB – 4 GB = 12 GB;12 GB 除以 4 GB(每 4 GB 得到 1 GB)为 3 GB。
- 2 GB,如 32 GB – 16 GB = 16 GB;16 除以 8(每个 8 GB 后 16 GB 得到 1 GB)是 2 GB 因此,对于具有 32 GB RAM 的服务器,总共将为操作系统保留 7 GB。这是分配给 SQL Server 的最大内存应该是 25 GB。同样,对于 64 GB 服务器,应为操作系统保留 10 GB,为 SQL Server 分配 54 GB。
为每 4GB RAM 分配 OS 1GB 背后的原因是什么?
假设我将 SQL Server 内存限制为 100 GB。
这是否仅将缓冲区限制为 100 GB,或者它是否还限制了查询内存授予?
我今天正在考虑类似的事情,但我找不到这条信息。
当 SQL Server 请求内存而操作系统无法提供时,我们会得到RESOURCE_SEMAPHORE
等待类型。
但我找不到如下信息:
假设查询要求 3GB。但是只能提供2,查询仍然运行缓慢,还是一直等待?
RESOURCE_SEMAPHORE
意味着查询处于“停止”状态,只是在等待内存?未决的内存授予应始终为 0 对吗?这意味着查询正在请求多少内存但仍在等待,对吗?
我正在阅读Memory Grants:Microsoft 的神秘 SQL Server memory consumer with Many Names,但它没有解释这一点,它只是解释了 Memory grant 是什么。
我们正在运行本地 SQL Server 2017 来支持数据仓库数据库。数据库通过 SSIS 按计划加载,主要是通过使用临时表和 MERGE 功能。最近,我们开始看到错误“资源池'内部'中的系统内存不足,无法运行此查询。”。在过去的几周里,它变得越来越猖獗。
我们尝试过:
- 关闭查询存储
- 通过 CU27 更新 SQL Server
- 跟踪查询(没有好的结果)
- 运行尽可能多的报告以查明问题
与错误发生时间相关的最新更改:
- 打开查询存储
- 添加大量索引
其他信息:
- 我们在服务器上有 32gb 的内存并分配 26gb 给 sql server
- MERGE 的 TARGET 表是一个 CLUSTERED COLUMNSTORE INDEX
- MERGE 的 SOURCE 表是一个 HEAP
- 随着时间/多次失败,已暂存更改记录的 SOURCE 表已增长到超过 200,000 条记录。TARGET 表大约有 1000 万行。
任何帮助,将不胜感激。我在过去的几天里搜索了互联网,寻找任何指导。到目前为止,我所看到的是:
- 更新 SQL 版本
- 修改您的查询
- 向服务器添加内存
合并声明:
DROP TABLE IF EXISTS #Changes;
DROP TABLE IF EXISTS #TransformedChanges;
CREATE TABLE #Changes
(
[Change Type] VARCHAR(100)
);
MERGE [dbo].[FactOrderLine] AS TARGET
USING ( SELECT
[FactOrderLine].[OrderLine_Key],
[FactOrderLine].[BookedDate_Date_Key],
[FactOrderLine].[BookedDate_Time_Key],
[FactOrderLine].[Account_Key],
[FactOrderLine].[CCN_Key],
[FactOrderLine].[BillTo_SalesOffice_Key],
[FactOrderLine].[BillTo_Territory_Key],
[FactOrderLine].[ShipTo_SalesOffice_Key],
[FactOrderLine].[ShipTo_Territory_Key],
[FactOrderLine].[AssemblyLocation_Key],
[FactOrderLine].[ProductDivision_Key],
[FactOrderLine].[Product_Key],
[FactOrderLine].[Booked Date],
[FactOrderLine].[Ordered Quantity],
[FactOrderLine].[Unit Price - CCN],
[FactOrderLine].[Unit Price - Transaction],
[FactOrderLine].[Discount Factor],
[FactOrderLine].[Split Factor],
[FactOrderLine].[Is Split?],
[DW_Checksum] = CHECKSUM([FactOrderLine].[BookedDate_Date_Key],
[FactOrderLine].[BookedDate_Time_Key],
[FactOrderLine].[Account_Key],
[FactOrderLine].[CCN_Key],
[FactOrderLine].[BillTo_SalesOffice_Key],
[FactOrderLine].[BillTo_Territory_Key],
[FactOrderLine].[ShipTo_SalesOffice_Key],
[FactOrderLine].[ShipTo_Territory_Key],
[FactOrderLine].[AssemblyLocation_Key],
[FactOrderLine].[ProductDivision_Key],
[FactOrderLine].[Product_Key],
[FactOrderLine].[Booked Date],
[FactOrderLine].[Ordered Quantity],
[FactOrderLine].[Unit Price - CCN],
[FactOrderLine].[Unit Price - Transaction],
[FactOrderLine].[Discount Factor],
[FactOrderLine].[Split Factor],
[FactOrderLine].[Is Split?],
0)
FROM [changeLog].[FactOrderLine] ) AS SOURCE
ON [Source].[OrderLine_Key] = [Target].[OrderLine_Key]
WHEN MATCHED AND ISNULL([Source].[DW_Checksum], 0) <> ISNULL([Target].[DW_Checksum], 0) THEN UPDATE SET
[Target].[BookedDate_Date_Key] = [Source].[BookedDate_Date_Key],
[Target].[BookedDate_Time_Key] = [Source].[BookedDate_Time_Key],
[Target].[Account_Key] = [Source].[Account_Key],
[Target].[CCN_Key] = [Source].[CCN_Key],
[Target].[BillTo_SalesOffice_Key] = [Source].[BillTo_SalesOffice_Key],
[Target].[BillTo_Territory_Key] = [Source].[BillTo_Territory_Key],
[Target].[ShipTo_SalesOffice_Key] = [Source].[ShipTo_SalesOffice_Key],
[Target].[ShipTo_Territory_Key] = [Source].[ShipTo_Territory_Key],
[Target].[AssemblyLocation_Key] = [Source].[AssemblyLocation_Key],
[Target].[ProductDivision_Key] = [Source].[ProductDivision_Key],
[Target].[Product_Key] = [Source].[Product_Key],
[Target].[Booked Date] = [Source].[Booked Date],
[Target].[Ordered Quantity] = [Source].[Ordered Quantity],
[Target].[Unit Price - CCN] = [Source].[Unit Price - CCN],
[Target].[Unit Price - Transaction] = [Source].[Unit Price - Transaction],
[Target].[Discount Factor] = [Source].[Discount Factor],
[Target].[Split Factor] = [Source].[Split Factor],
[Target].[Is Split?] = [Source].[Is Split?],
[Target].[DW_Checksum] = [Source].[DW_Checksum],
[Target].[DW_ModifiedOn] = GETUTCDATE(),
[Target].[DW_IsDeleted?] = 0
WHEN NOT MATCHED BY TARGET THEN INSERT
(
[OrderLine_Key],
[BookedDate_Date_Key],
[BookedDate_Time_Key],
[Account_Key],
[CCN_Key],
[BillTo_SalesOffice_Key],
[BillTo_Territory_Key],
[ShipTo_SalesOffice_Key],
[ShipTo_Territory_Key],
[AssemblyLocation_Key],
[ProductDivision_Key],
[Product_Key],
[Booked Date],
[Ordered Quantity],
[Unit Price - CCN],
[Unit Price - Transaction],
[Discount Factor],
[Split Factor],
[Is Split?],
[DW_IsDeleted?], [DW_Checksum], [Source_ModifiedOn], [DW_ModifiedOn], [DW_CreatedOn] ) VALUES (
[Source].[OrderLine_Key],
[Source].[BookedDate_Date_Key],
[Source].[BookedDate_Time_Key],
[Source].[Account_Key],
[Source].[CCN_Key],
[Source].[BillTo_SalesOffice_Key],
[Source].[BillTo_Territory_Key],
[Source].[ShipTo_SalesOffice_Key],
[Source].[ShipTo_Territory_Key],
[Source].[AssemblyLocation_Key],
[Source].[ProductDivision_Key],
[Source].[Product_Key],
[Source].[Booked Date],
[Source].[Ordered Quantity],
[Source].[Unit Price - CCN],
[Source].[Unit Price - Transaction],
[Source].[Discount Factor],
[Source].[Split Factor],
[Source].[Is Split?],
0,
[Source].[DW_Checksum],NULL,GETUTCDATE(),GETUTCDATE()
)
OUTPUT $action INTO #Changes;
CREATE TABLE #TransformedChanges
(
[Update Record Count] INT,
[Insert Record Count] INT
);
INSERT INTO #TransformedChanges
SELECT *
FROM
(
SELECT
TRIM(#Changes.[Change Type])+' Record Count' AS [Change Type],
COUNT(*) AS [Record Count]
FROM #Changes
GROUP BY TRIM(#Changes.[Change Type])+' Record Count'
) A
PIVOT
(
SUM([Record Count])
FOR A.[Change Type] IN ([Update Record Count], [Insert Record Count])
) [B];
DECLARE @TransformationChecker INT;
SET @TransformationChecker = (SELECT COUNT(*) FROM #TransformedChanges);
IF @TransformationChecker = 0 INSERT INTO #TransformedChanges VALUES(0,0);
SELECT ISNULL([Update Record Count], 0) [Update Record Count], ISNULL([Insert Record Count], 0) [Insert Record Count] FROM #TransformedChanges;
DROP TABLE IF EXISTS #Changes;
DROP TABLE IF EXISTS #TransformedChanges;
这是在 SQL Server 2019 上,在具有 64GB 或 RAM 的 Windows 10 上运行。尝试解决内存问题时,我发现了使用以下查询的帖子:
SELECT virtual_address_space_reserved_kb as Reserved,
virtual_address_space_committed_kb Committed,
physical_memory_in_use_kb as Physical
FROM sys.dm_os_process_memory
在我的服务器上运行查询产生了以下结果:
Reserved Committed Physical
101,881,000 3,123,124 2,747,764
所以提交的内存不仅仅是物理内存。我觉得这很奇怪,所以我重新启动了服务器,再次运行查询,数字改变了,但 Committed 仍然大于 Physical:
Reserved Committed Physical
102,000,616 2,259,624 1,743,392
这正常吗?如果没有,我的服务器是否有严重问题?
内容为:配置固定内存量的过程(不推荐)
为什么它说程序“不推荐”?
我想升级 SQL Server 内存,那么推荐的程序是什么?
我有一个存储过程,它将三个大表连接在一起(每个大约 2000 万条记录)并将记录加载到一个临时表中。然后将临时表中的数据合并到一个包含大约 6000 万条记录的现有表中。
服务器离线并显示以下错误消息:
由于内存压力,AppDomain 2 (SSISDB.dbo.[runtime].1] 被标记为卸载。
让服务器重新联机后,我重新启动 SQL 服务以清除任何可能一直存在的进程。再次开始工作,并且没有问题地完成。
我正在运行具有 128GB RAM 的 SQL Server 2019。64 位虚拟服务器上的最大服务器内存为 117964MB。有人在任务管理器中告诉我内存使用率为 94%,这可能是问题所在。但是 SQL 不会占用所有可用内存并保留它吗?所以看起来它正在按预期运行。
sp_WhoIsActive
揭示了一些状态为“暂停”和“等待命令”的查询,但我认为这些不会产生太大影响。128GB 的内存似乎足够了,但我想这与它被要求做的工作有关。知道如何排除故障或防止再次发生吗?
服务器的数据驱动器约为 1.6TB。连接中的两个较大的数据库是 10GB 的 1900 万行和 13GB 的 2000 万行。这些进入一个临时表,然后MERGE
进入一个有 5300 万行的 26GB 表。
请求的内存授权为 45GB,实际为 30GB。这项工作是在正常工作时间之外进行的,所以应该没有竞争性查询,但我不能 100% 确认有人没有工作到很晚。
我确实注意到它也必须这样做CONVERT_IMPLICIT
。这对所需的内存有重大影响吗?
查询计划链接: https ://www.brentozar.com/pastetheplan/?id=SyXaty7xK
我的 mongod 命令
mongod --wiredTigerCacheSizeGB 5
在实践中,我让 mongo 实例使用甚至高达 8.6 GB(在具有 50 GB RAM 的 VM 上)
索引使用大约 100 MB(用 选中db.stats()
)
tcmalloc 信息:
MALLOC: 3776745552 ( 3601.8 MiB) Bytes in use by application
MALLOC: + 4744544256 ( 4524.8 MiB) Bytes in page heap freelist
MALLOC: + 20067616 ( 19.1 MiB) Bytes in central cache freelist
MALLOC: + 3584128 ( 3.4 MiB) Bytes in transfer cache freelist
MALLOC: + 12470800 ( 11.9 MiB) Bytes in thread cache freelists
MALLOC: + 22544384 ( 21.5 MiB) Bytes in malloc metadata
MALLOC: ------------
MALLOC: = 8579956736 ( 8182.5 MiB) Actual memory used (physical + swap)
MALLOC: + 29933568 ( 28.5 MiB) Bytes released to OS (aka unmapped)
MALLOC: ------------
MALLOC: = 8609890304 ( 8211.0 MiB) Virtual address space used
MALLOC:
MALLOC: 21650 Spans in use
MALLOC: 59 Thread heaps in use
MALLOC: 4096 Tcmalloc page size
服务器已经运行了 3 天。
我怎么知道为什么 mongo 消耗的内存超过了允许的缓存大小?有没有办法手动释放“页堆空闲列表”?
命令输出是推荐的Call ReleaseFreeMemory() to release freelist memory to the OS
,但我认为我实际上不能在这个过程之外做到这一点。
MongoDB 版本是4.4.1
,我使用的是mongo:4.4.1-bionic
docker 镜像。
问题
我们启用了 sp_configure 'tempdb metadata memory-optimized' = 1,现在 tempdb 元数据在我们的一台服务器上占用了 400 GB 以上,并且还在继续增长。内存使用量有所下降,但通常它会不断增长它的内存使用量。我们已经有几次服务器实际上崩溃了,因为没有足够的内存供其他系统进程修改 tempdb 并导致整个服务器停机。
我要问的问题
如何防止 SQL Server 内存中优化的 tempdb 元数据持续增长并使我的服务器崩溃?如果有的话,我可以查看哪些其他信息来找出消耗这么多内存的原因?
有关问题的数据
sys.dm_os_memory_clerks
以下查询当前返回 438 GB。
SELECT SUM(domc.pages_kb / 1024.0 / 1024.0) AS pages_gb
FROM sys.dm_os_memory_clerks AS domc
WHERE domc.type LIKE 'MEMORYCLERK_XTP'
sys.dm_db_xtp_memory_consumers
以下查询提供了内存使用量最大 (290 GB) 为 memory_consumer_id of 113 - 'LOB Page Allocator' 的数据。它没有object_id 或xtp_object_id,所以我猜它是一个数据库范围的对象。
SELECT ddxmc.memory_consumer_id
, ddxmc.memory_consumer_type_desc
, ddxmc.memory_consumer_desc
, ddxmc.object_id
, ddxmc.xtp_object_id
, ddxmc.used_bytes / 1024.0 / 1024.0 / 1024.0 AS used_gb
FROM sys.dm_db_xtp_memory_consumers AS ddxmc
ORDER BY ddxmc.allocated_bytes DESC
环境
版本:SQL Server 2019 CU9 -
机箱上的企业内存:3 TB
实例类型:故障转移集群实例
操作系统:Windows Server 2019 标准
CPU 核心数:80 个物理核心(我们最近不得不增加这个数字) Tempdb 的数量文件:64 复制:此服务器是事务复制的发布者和订阅者。
使用模式
我们是 tempdb 的重度用户。我们一直在存储过程中不断地创建和删除临时表和表变量。我们需要处理大量数据,传入数据列表,然后将这些数据列表转换为表格来处理结果集数据,而不是一次处理一条信息。由于 tempdb 的大量流失,我们不得不实现内存中优化的 tempdb 以减轻我们遇到的 PAGELATCH_* 等待。
我很确定没有任何内存优化的用户表。当我运行以下查询时,我只看到SYSTEM_TABLE
类型对象:
SELECT *
FROM sys.dm_db_xtp_index_stats AS ddxis
JOIN sys.objects AS o ON o.object_id = ddxis.object_id
我知道的事情和我尝试过的事情
内存垃圾收集只能清理比最旧事务更早的项目。
我很清楚垃圾收集只能发生在比最旧事务更早的行上,因此我已经停止了所有长时间运行的 SQL 代理作业和任何其他超过 5 分钟的进程。不幸的是,我们的内存使用量并没有回落。我们确实有旧会话,但根据以下查询,它们都没有打开任何事务。
SELECT *
FROM sys.dm_exec_sessions AS des
WHERE des.open_transaction_count > 0
复制
为了排除复制,我确实暂时停止了此服务器的发布和订阅代理。内存使用没有变化。
检查点
我在 tempdb 中运行了“CHECKPOINT”。内存使用量没有下降。
DBCC FREEPROCCACHE - 摆脱旧的临时表
为了删除正在缓存的旧临时表,我清除了查询计划缓存,并通过运行以下查询验证了临时表是否已重新创建。这并没有导致内存使用量大幅下降。
SELECT *
FROM sys.tables AS t
WHERE t.name LIKE '#%'
AND t.create_date < 'TimeOfClearingPlanCache'
其他可能的解决方案
重新启动 SQL Server
我们可以重新启动 SQL Server,它确实可以缓解一段时间的问题,但一段时间后内存使用量确实会再次增加。虽然这是一种解决方法,但这是一个我们不太喜欢的糟糕解决方案。
关闭“内存中优化的 Tempdb”
我们可以关闭“内存中优化的 tempdb”,但是我们会受到我们之前经历过的大量 PAGELATCH_* 等待的影响。我们有 64 个 tempdb 文件来帮助减少我们看到的争用,但在我们繁忙的时期,即使这样也不够。这可能是一种选择,但最好是我们能找到内存使用量持续增长的原因。