다음을 통해 공유


SQL Server의 메모리 부족 문제 해결

증상

SQL Server는 복잡하고 풍부한 기능 집합에 해당하는 복잡한 메모리 아키텍처 를 사용합니다. 메모리 요구 사항이 다양하기 때문에 메모리 사용량과 메모리 압력의 많은 원본이 있을 수 있으며 궁극적으로 메모리 부족 상태가 발생할 수 있습니다.

SQL Server의 메모리가 낮음을 나타내는 일반적인 오류가 있습니다. 오류의 예는 다음과 같습니다.

  • 701: 쿼리를 실행하기에 충분한 메모리를 할당하지 못했습니다.
  • 802: 버퍼 풀(데이터 또는 인덱스 페이지)에서 페이지를 할당하는 메모리를 얻지 못했습니다.
  • 1204: 잠금을 위해 메모리를 할당하지 못했습니다.
  • 6322: XML 파서에 대한 메모리를 할당하지 못했습니다.
  • 6513:메모리 압력으로 인해 CLR을 초기화하지 못했습니다.
  • 6533: 메모리 부족으로 인해 AppDomain이 언로드되었습니다.
  • 8318: 메모리 부족으로 인해 SQL 성능 카운터를 로드하지 못했습니다.
  • 8356 또는 8359: 메모리 부족으로 인해 ETW 또는 SQL 추적이 실행되지 않습니다.
  • 8556: 메모리 부족으로 인해 MSDTC를 로드하지 못했습니다.
  • 8645: 메모리 부여(정렬 및 해시)에 대한 메모리가 없어 쿼리를 실행하지 못했습니다. 자세한 내용은 SQL Server 오류 8645 문제를 해결하는 방법을 참조하세요.
  • 8902: DBCC를 실행하는 동안 메모리를 할당하지 못했습니다.
  • 9695 또는 9696: Service Broker 작업에 메모리를 할당하지 못했습니다.
  • 17131 또는 17132: 메모리 부족으로 인한 서버 시작 실패
  • 17890: OS에서 페이징되는 SQL 메모리로 인해 메모리를 할당하지 못했습니다.
  • 18053: 서식을 지정하는 동안 오류가 발생했기 때문에 오류가 어둡게 모드로 인쇄됩니다. 추적, ETW, 알림 등은 생략됩니다.
  • 22986 또는 22987: 메모리 부족으로 인한 데이터 캡처 오류를 변경합니다.
  • 25601: Xevent 엔진의 메모리가 부족합니다.
  • 26053: 메모리 부족으로 인해 SQL 네트워크 인터페이스를 초기화하지 못합니다.
  • 30085, 30086, 30094: 메모리 부족으로 인해 SQL 전체 텍스트 작업이 실패합니다.

원인

많은 요인으로 인해 메모리가 부족해질 수 있습니다. 이러한 요인에는 운영 체제 설정, 실제 메모리 가용성, SQL Server 내에서 메모리를 사용하는 구성 요소 및 현재 워크로드의 메모리 제한이 포함됩니다. 대부분의 경우 메모리 부족 오류로 인해 실패하는 쿼리는 이 오류의 원인이 아닙니다. 전반적으로 원인은 다음 세 가지 범주로 그룹화할 수 있습니다.

원인 1: 외부 또는 OS 메모리 압력

외부 압력은 프로세스 외부 구성 요소에서 발생하는 높은 메모리 사용률을 의미하며, 이로 인해 SQL Server 메모리가 부족해집니다. 시스템의 다른 애플리케이션이 메모리를 사용하고 메모리 가용성이 낮은지 확인해야 합니다. SQL Server는 메모리 사용을 줄여 OS 메모리 압력에 응답하도록 설계된 몇 안 되는 애플리케이션 중 하나입니다. 즉, 애플리케이션 또는 드라이버가 메모리를 요청하는 경우 OS는 모든 애플리케이션에 신호를 보내 메모리를 확보하고 SQL Server는 자체 메모리 사용량을 줄여 응답합니다. 다른 애플리케이션은 해당 알림을 수신하도록 설계되지 않았기 때문에 응답하지 않습니다. 따라서 SQL Server가 메모리 사용량을 줄이기 시작하면 메모리 풀이 줄어들고 메모리가 필요한 구성 요소 중 어느 것이라도 메모리를 얻지 못할 수 있습니다. 따라서 701 또는 기타 메모리 관련 오류가 발생합니다. SQL이 동적으로 메모리를 할당하고 해제하는 방법에 대한 자세한 내용은 SQL Server 메모리 아키텍처를 참조 하세요. 문제에 대한 자세한 진단 및 해결 방법은 이 문서의 외부 메모리 압력을 참조하세요.

OS 메모리 압력을 일으킬 수 있는 세 가지 광범위한 문제 범주가 있습니다.

  • 애플리케이션 관련 문제: 하나 이상의 애플리케이션이 함께 사용 가능한 실제 메모리를 소모합니다. OS는 일부 메모리를 해제하여 리소스에 대한 새 애플리케이션 요청에 응답합니다. 일반적인 방법은 메모리를 소모하는 애플리케이션을 찾고 RAM 고갈을 초래하지 않고 메모리를 분산하는 데 필요한 단계를 수행하는 것입니다.
  • 디바이스 드라이버 문제: 드라이버가 메모리 할당 함수를 잘못 호출하는 경우 디바이스 드라이버로 인해 모든 프로세스의 작업 집합 페이징이 발생할 수 있습니다.
  • 운영 시스템 제품 문제입니다.

이러한 단계 및 문제 해결 단계에 대한 자세한 설명은 MSSQLSERVER_17890 참조하세요.

원인 2: SQL Server에서 들어오지 않는 내부 메모리 압력

내부 메모리 압력은 SQL Server 프로세스 내부 요인으로 인해 발생하는 낮은 메모리 가용성을 의미합니다. SQL Server 프로세스 내에서 실행할 수 있는 일부 구성 요소는 SQL Server 엔진에 대한 "외부"입니다. 예를 들어 연결된 서버, SQLCLR 프로시저 또는 함수, 확장 프로시저(XP) 및 OLE 자동화()와 같은 OLE DB 공급자(sp_OA*DLL)가 있습니다. 그 외에는 모니터링 목적으로 프로세스 내에 DLL을 삽입하는 바이러스 백신 또는 기타 보안 프로그램이 포함됩니다. 이러한 구성 요소 중에서 문제가 발생하거나 설계가 잘못되면 메모리 사용량이 커질 수 있습니다. 예를 들어 외부 원본에서 SQL Server 메모리로 2천만 행의 데이터를 캐싱하는 연결된 서버를 고려합니다. SQL Server의 경우 메모리 클럭은 높은 메모리 사용량을 보고하지 않지만 SQL Server 프로세스 내에서 사용되는 메모리는 높아집니다. 예를 들어 연결된 서버 DLL에서 메모리가 증가하면 SQL Server에서 메모리 사용량(위 참조)을 자르기 시작하고 SQL Server 내의 구성 요소에 대한 메모리 부족 조건이 생성되어 메모리 부족 오류가 발생합니다. 이 문제에 대한 자세한 진단 및 해결 방법은 SQL Server에서 오는 것이 아니라 내부 메모리 압력을 참조 하세요.

참고 항목

SQL Server 프로세스 공간(예 : MSOLEDBSQL, SQL Native Client)에 사용되는 몇 가지 Microsoft DLL은 보고 및 할당을 위해 SQL Server 메모리 인프라와 인터페이스할 수 있습니다. 실행 select * from sys.dm_os_memory_clerks where type='MEMORYCLERK_HOST' 하여 해당 목록을 가져와서 일부 할당에 대한 메모리 사용량을 추적할 수 있습니다.

원인 3: SQL Server 구성 요소에서 발생하는 내부 메모리 압력

SQL Server 엔진 내의 구성 요소에서 발생하는 내부 메모리 압력으로 인해 메모리 부족 오류가 발생할 수도 있습니다. SQL Server에서 메모리를 할당하는 메모리 클럭을 통해 추적되는 수백 개의 구성 요소가 있습니다. 이 문제를 해결하려면 가장 큰 메모리 할당을 담당하는 메모리 클럭을 식별해야 합니다. 예를 들어 메모리 클럭에 OBJECTSTORE_LOCK_MANAGER 큰 메모리 할당이 표시되는 경우 잠금 관리자가 너무 많은 메모리를 사용하는 이유를 이해해야 합니다. 많은 잠금을 획득하는 쿼리가 있을 수 있습니다. 인덱스를 사용하거나, 오랫동안 잠금을 보유하는 트랜잭션을 줄이거나, 잠금 에스컬레이션을 사용하지 않도록 설정했는지 확인하여 이러한 쿼리를 최적화할 수 있습니다. 각 메모리 클럭 또는 구성 요소에는 메모리에 액세스하고 사용하는 고유한 방법이 있습니다. 자세한 내용은 메모리 클럭 유형 및 해당 설명을 참조하세요. 이 문제에 대한 자세한 진단 및 해결 방법은 SQL Server 엔진의 내부 메모리 사용량을 참조하세요.

메모리 압력 형식의 시각적 표현

다음 그래프는 SQL Server의 메모리 부족 상태로 이어질 수 있는 압력 유형을 보여 줍니다.

메모리 압력 형식의 스크린샷

문제 해결 데이터를 수집하는 진단 도구

다음 진단 도구를 사용하여 문제 해결 데이터를 수집할 수 있습니다.

성능 모니터

성능 모니터를 사용하여 다음 카운터를 구성하고 수집합니다.

  • 메모리:사용 가능한 MBytes
  • Process:Working Set
  • Process:Private Bytes
  • SQL Server:Memory Manager: (모든 카운터)
  • SQL Server:Buffer Manager: (모든 카운터)

DMV 또는 DBCC MEMORYSTATUS

sys.dm_os_memory_clerks 또는 DBCC MEMORYSTATUS를 사용하여 SQL Server 내에서 전체 메모리 사용량을 관찰할 수 있습니다.

SSMS의 메모리 사용량 표준 보고서

SQL Server Management Studio에서 메모리 사용량 보기:

  1. SQL Server Management Studio를 시작하고 서버에 연결합니다.
  2. 개체 탐색기 SQL Server 인스턴스 이름을 마우스 오른쪽 단추로 클릭합니다.
  3. 상황에 맞는 메뉴에서 보고서>표준 보고서>메모리 사용량을 선택합니다.

PSSDiag 또는 SQL LogScout

이러한 데이터 요소를 캡처하는 자동화된 대안은 PSSDiag 또는 SQL LogScout과 같은 도구를 사용하는 것입니다.

  • PSSDiag를 사용하는 경우 Perfmon 수집기 및 사용자 지정 진단\SQL 메모리 오류 수집기를 캡처하도록 구성합니다.

  • SQL LogScout을 사용하는 경우 메모리 시나리오를 캡처하도록 구성합니다.

다음 섹션에서는 각 시나리오(외부 또는 내부 메모리 압력)에 대한 자세한 단계를 설명합니다.

문제 해결 방법

메모리 부족 오류가 가끔 나타나거나 짧은 기간 동안 발생하는 경우 수명이 짧은 메모리 문제가 발생할 수 있습니다. 이러한 경우에는 조치를 취할 필요가 없습니다. 그러나 오류가 여러 연결에서 여러 번 발생하고 몇 초 이상 지속되는 경우 다음 섹션의 진단 및 솔루션에 따라 메모리 오류를 추가로 해결합니다.

외부 메모리 압력

SQL Server 프로세스 외부의 시스템에서 메모리 부족 상태를 진단하려면 다음 방법을 사용합니다.

  • 성능 모니터 카운터를 수집합니다. SQL Server 이외의 애플리케이션 또는 서비스가 다음 카운터를 확인하여 이 서버에서 메모리를 사용하는지 조사합니다.

    • 메모리:사용 가능한 MBytes
    • Process:Working Set
    • Process:Private Bytes

    PowerShell을 사용하는 Perfmon 로그 컬렉션의 예는 다음과 같습니다.

    clear
    $serverName = $env:COMPUTERNAME
    $Counters = @(
       ("\\$serverName" +"\Memory\Available MBytes"),
       ("\\$serverName" +"\Process(*)\Working Set"),
       ("\\$serverName" +"\Process(*)\Private Bytes")
    )
    
    Get-Counter -Counter $Counters -SampleInterval 2 -MaxSamples 1 | ForEach-Object  {
    $_.CounterSamples | ForEach-Object   {
       [pscustomobject]@{
          TimeStamp = $_.TimeStamp
          Path = $_.Path
          Value = ([Math]::Round($_.CookedValue, 3)) }
    }
    }
    
  • 시스템 이벤트 로그를 검토하고 메모리 관련 오류(예: 낮은 가상 메모리)를 찾습니다.

  • 애플리케이션 관련 메모리 문제의 경우 애플리케이션 이벤트 로그를 검토합니다.

    다음은 시스템 및 애플리케이션 이벤트 로그에서 "memory" 키워드를 쿼리하는 PowerShell 스크립트의 예입니다. 검색에 "리소스"와 같은 다른 문자열을 자유롭게 사용할 수 있습니다.

    Get-EventLog System -ComputerName "$env:COMPUTERNAME" -Message "*memory*"
    Get-EventLog Application -ComputerName "$env:COMPUTERNAME" -Message "*memory*"
    
  • 덜 중요한 애플리케이션 또는 서비스에 대한 코드 또는 구성 문제를 해결하여 메모리 사용량을 줄입니다.

  • SQL Server 외에 애플리케이션에서 리소스를 사용하는 경우 이러한 애플리케이션을 중지하거나 다시 예약하거나 별도의 서버에서 실행하는 것이 좋습니다. 이렇게 하면 외부 메모리 가중을 없앨 수 있습니다.

SQL Server에서 발생하지 않는 내부 메모리 압력

SQL Server 내의 모듈(DLL)로 인한 내부 메모리 압력을 진단하려면 다음 방법을 사용합니다.

  • SQL Server가 AWE API(메모리의 잠긴 페이지)를 사용하지 않는 경우 대부분의 메모리가 성능 모니터 Process:Private Bytes 카운터(SQLServr인스턴스)에 반영됩니다. SQL Server 엔진 내에서 들어오는 전체 메모리 사용량은 SQL Server:Memory Manager: 총 서버 메모리(KB) 카운터에 반영됩니다. Process:Private BytesSQL Server:Memory Manager: Total Server Memory(KB)간에 상당한 차이가 있는 경우 해당 차이는 DLL(연결된 서버, XP, SQLCLR 등)에서 발생할 수 있습니다. 예를 들어 프라이빗 바이트가 300GB이고 총 서버 메모리가 250GB인 경우 프로세스의 전체 메모리 약 50GB가 SQL Server 엔진 외부에서 제공됩니다.

  • SQL Server가 AWE API(메모리의 잠긴 페이지)를 사용하는 경우 성능 모니터 개별 프로세스에 대한 메모리 사용량을 추적하는 AWE 카운터를 제공하지 않으므로 문제를 식별하기가 더 어렵습니다. SQL Server 엔진 내의 전체 메모리 사용량은 SQL Server:Memory Manager: 총 서버 메모리(KB) 카운터에 반영됩니다. 일반적인 Process:Private Bytes 값은 전체적으로 300MB에서 1~2GB 사이일 수 있습니다. 이 일반적인 사용 외에 Process:Private 바이트를 많이 사용하는 경우 DLL(연결된 서버, XP, SQLCLR 등)에서 차이가 발생할 수 있습니다. 예를 들어 프라이빗 바이트 카운터가 4-5GB이고 SQL Server가 AWE(메모리의 잠긴 페이지)를 사용하는 경우 프라이빗 바이트의 상당 부분이 SQL Server 엔진 외부에서 제공될 수 있습니다. 이는 근사치 기법입니다.

  • Tasklist 유틸리티를 사용하여 SQL Server 공간 내에 로드되는 DLL을 식별합니다.

    tasklist /M /FI "IMAGENAME eq sqlservr.exe"
    
  • 다음 쿼리를 사용하여 로드된 모듈(DLL)을 검사하고 예기치 않은 항목이 있는지 확인할 수도 있습니다.

    SELECT * FROM sys.dm_os_loaded_modules
    
  • 연결된 서버 모듈이 상당한 메모리 소비를 유발하는 것으로 의심되는 경우 처리 허용 옵션을 사용하지 않도록 설정하여 프로세스가 부족하도록 구성할 수 있습니다. 자세한 내용은 연결된 서버 만들기를 참조하세요. 모든 연결된 서버 OLE DB 공급자가 프로세스가 부족할 수 있는 것은 아닙니다. 자세한 내용은 제품 제조업체에 문의하세요.

  • 드물게 OLE 자동화 개체(sp_OA*)가 사용되는 경우 컨텍스트 값 4(로컬(.exe) OLE 서버만 지정하여 SQL Server 외부의 프로세스에서 실행되도록 개체를 구성할 수 있습니다. 자세한 내용은 sp_OACreate를 참조하세요.

SQL Server 엔진의 내부 메모리 사용량

SQL Server 엔진 내의 구성 요소에서 발생하는 내부 메모리 압력을 진단하려면 다음 방법을 사용합니다.

  • SQL Server: SQL Server:Buffer Manager 및 SQL Server: Memory Manager에 대한 성능 모니터 카운터 수집을 시작합니다.

  • SQL Server 메모리 클럭 DMV를 여러 번 쿼리하여 엔진 내에서 가장 높은 메모리 사용량이 발생하는 위치를 확인합니다.

    SELECT pages_kb, type, name, virtual_memory_committed_kb, awe_allocated_kb
    FROM sys.dm_os_memory_clerks
    ORDER BY pages_kb DESC
    
  • 또는 이러한 오류 메시지가 표시될 때 보다 자세한 DBCC MEMORYSTATUS 출력과 변경 방식을 관찰할 수 있습니다.

    DBCC MEMORYSTATUS
    
  • 메모리 클럭 중 명확한 위반자를 식별하는 경우 해당 구성 요소의 메모리 사용량 세부 사항을 해결하는 데 집중합니다. 다음은 몇 가지 예입니다.

    • 메모리 클럭 MEMORYCLERK_SQLQERESERVATIONS 이 메모리를 사용하는 경우 거대한 메모리 부여를 사용하는 쿼리를 식별하고 인덱스를 통해 최적화하거나, 다시 작성하거나(예: 제거ORDER by) 메모리 부여 쿼리 힌트를 적용합니다(min_grant_percent 및 max_grant_percent 힌트 참조). 메모리 부여 메모리의 사용을 제어하는 리소스 관리자 풀을 만들 수도 있습니다. 메모리 부여에 대한 자세한 내용은 SQL Server의 메모리 부여로 인한 성능 저하 또는 메모리 부족 문제 해결을 참조하세요.
    • 많은 수의 임시 쿼리 계획이 캐시되는 CACHESTORE_SQLCP 경우 메모리 클럭은 많은 양의 메모리를 사용합니다. 쿼리 계획을 다시 사용할 수 없는 매개 변수가 없는 쿼리를 식별하고 저장 프로시저로 변환하거나, 사용 sp_executesql하거나, 매개 변수화를 사용하여 FORCED 매개 변수화합니다. 추적 플래그 174사용하도록 설정한 경우 이 플래그를 사용하지 않도록 설정하여 문제가 해결되었는지 확인할 수 있습니다.
    • 개체 계획 캐시 저장소 CACHESTORE_OBJCP 가 너무 많은 메모리를 사용하는 경우 많은 양의 메모리를 사용하는 저장 프로시저, 함수 또는 트리거를 식별하고 애플리케이션을 다시 디자인할 수 있습니다. 일반적으로 이 오류는 각각에 수백 개의 프로시저가 있는 많은 양의 데이터베이스 또는 스키마로 인해 발생할 수 있습니다.
    • 메모리 클럭에 OBJECTSTORE_LOCK_MANAGER 큰 메모리 할당이 표시되면 많은 잠금을 적용하는 쿼리를 식별하고 인덱스를 사용하여 최적화합니다. 특정 격리 수준에서 잠금이 장기간 해제되지 않도록 하는 트랜잭션을 줄이거나 잠금 에스컬레이션을 사용하지 않도록 설정되었는지 확인합니다.
    • 매우 큰 TokenAndPermUserStore 경우(select type, name, pages_kb from sys.dm_os_memory_clerks where name = 'TokenAndPermUserStore') 추적 플래그 4618을 사용하여 캐시 크기를 제한할 수 있습니다.
    • 메모리 내 OLTP에서 MEMORYCLERK_XTP 발생하는 메모리 내 OLTP 문제를 관찰하는 경우 메모리 내 OLTP 및 메모리 최적화 tempdb 메타데이터(HkTempDB)의 메모리 부족 오류에 대한 메모리 사용 모니터링 및 문제 해결을 참조할 수 있습니다.

메모리를 사용할 수 있도록 빠른 완화

다음 작업은 일부 메모리를 해제하고 SQL Server에서 사용할 수 있도록 할 수 있습니다.

메모리 구성 설정 변경

다음 SQL Server 메모리 구성 매개 변수를 확인하고 가능한 경우 최대 서버 메모리를 늘리는 것이 좋습니다.

  • 최대 서버 메모리
  • 최소 서버 메모리

참고 항목

비정상적인 설정이 발견되면 필요에 따라 수정하고 메모리 요구 사항 증가를 고려합니다. 기본 설정은 서버 메모리 구성 옵션에 나열되어 있습니다.

최대 서버 메모리를 구성하지 않은 경우, 특히 메모리의 잠긴 페이지를 사용하여 OS에 대한 일부 메모리를 허용하도록 특정 값으로 설정하는 것이 좋습니다. 메모리 서버 구성의 잠긴 페이지를 참조하세요.

시스템에서 워크로드 변경 또는 이동

쿼리 워크로드를 조사합니다. 동시 세션 수, 현재 실행 중인 쿼리 수 및 일시적으로 중지되거나 다른 SQL Server로 이동할 수 있는 덜 중요한 애플리케이션이 있는지 확인합니다.

읽기 전용 워크로드의 경우 Always On 환경에서 읽기 전용 보조 복제본으로 이동하는 것이 좋습니다. 자세한 내용은 읽기 전용 워크로드를 Always On 가용성 그룹의 보조 복제본으로 오프로드하고 Always On 가용성 그룹의 보조 복제본에 대한 읽기 전용 액세스 구성을 참조하세요.

가상 머신에 대한 적절한 메모리 구성 확인

VM(가상 머신)에서 SQL Server를 실행하는 경우 VM의 메모리가 과도하게 커밋되지 않았는지 확인합니다. VM 에 대한 메모리를 구성하는 방법에 대한 아이디어는 가상화 - 오버 커밋 메모리 및 VM 내에서 메모리를 검색하고 ESX/ESXi 가상 머신 성능 문제 해결(메모리 초과 커밋)을 참조하세요.

SQL Server 내의 메모리 해제

다음 DBCC 명령 중 하나 이상을 실행하여 여러 SQL Server 메모리 캐시를 해제할 수 있습니다.

  • DBCC FREESYSTEMCACHE

  • DBCC FREESESSIONCACHE

  • DBCC FREEPROCCACHE

SQL Server 서비스 다시 시작

경우에 따라 메모리의 심각한 고갈을 처리해야 하고 SQL Server가 쿼리를 처리할 수 없는 경우 서비스를 다시 시작하는 것이 좋습니다.

특정 시나리오에 Resource Governor를 사용하는 것이 좋습니다.

리소스 관리자를 사용하는 경우 리소스 풀 및 워크로드 그룹 설정을 확인하여 메모리를 너무 크게 제한하지 않는지 확인하는 것이 좋습니다.

물리적 또는 가상 서버에 RAM 추가

문제가 계속되면 더 자세히 조사하고 RAM(서버 리소스)을 늘려야 합니다.