이 문서에서는 SQL Server에서 대규모 작업 일괄 처리를 실행할 때 발생할 수 있는 701 오류에 대해 설명합니다. 701 오류의 다른 원인은 MSSQLSERVER_701 참조하세요.
원래 제품 버전: SQL Server
원래 KB 번호: 2001221
증상
SQL Server에서 RPC(원격 프로시저 호출)의 대규모 일괄 처리를 실행하는 경우(예: 단일 일괄 처리에서 수만 개의 삽입) SQL Server 오류 로그에 보고된 다음 오류로 작업이 실패할 수 있습니다.
2020-07-04 13:30:45.78 spid56 Error: 701, Severity: 17, State: 193.
2020-07-04 13:30:45.78 spid56 There is insufficient system memory to run this query.
701 오류 메시지의 오류 로그에 자동으로 기록되는 DBCC MEMORYSTATUS 의 출력을 확인하면 다음과 같은 항목을 찾을 수 있습니다.
2020-07-04 13:30:45.74 spid56 Failed allocate pages: FAIL_PAGE_ALLOCATION 1
2020-07-04 13:30:45.76 spid58
Memory Manager
VM Reserved = 1657936 KB
VM Committed = 66072 KB
AWE Allocated = 2351104 KB ==> ~2.2 GB
Reserved Memory = 1024 KB
Reserved Memory In Use = 0 KB
2020-07-04 13:30:45.76 spid56
USERSTORE_SXC (Total)
VM Reserved = 0 KB
VM Committed = 0 KB
AWE Allocated = 0 KB
SM Reserved = 0 KB
SM Committed = 0 KB
SinglePage Allocator = 1127848 KB==> ~1.07 GB
MultiPage Allocator = 0 KB
2020-07-04 13:30:45.78 spid56 Error: 701, Severity: 17, State: 193.
2020-07-04 13:30:45.78 spid56 There is insufficient system memory to run this query.
참고 항목
캐시 USERSTORE_SXC
에 대한 대용량 할당을 확인합니다.
또한 일괄 처리가 실행되는 동안 sys.dm_os_memory_clerkssingle_pages_kb
하는 경우 캐시의 열 USERSTORE_SXC
은 701 오류를 생성하는 기간 동안 지속적으로 증가합니다.
잠재적으로 이 동작을 나타낼 수 있는 애플리케이션의 예는 자세한 내용을 참조하세요.
원인
SQL Server에 요청을 저장하기 위해 할당된 메모리 양은 다음에 따라 달라집니다.
- 일괄 처리 크기(요청당 RPC 수)입니다.
- 매개 변수 수입니다.
- 매개 변수의 형식입니다.
특정 유형의 매개 변수(예: sql_variant)의 경우 SQL Server는 잠재적으로 비효율적인 방식으로 메모리에 요청을 저장할 수 있습니다. 클라이언트가 이러한 유형의 매개 변수를 사용하는 대량의 요청을 보내는 경우 여러 RPC를 하나의 요청으로 보낼 수 있습니다. 이 시나리오에서는 서버가 실행되기 전에 전체 요청을 메모리에 누적합니다. 이로 인해 증상에 설명된 701 오류가 발생할 수 있습니다.
이 문제는 이전 버전의 SQL Server에서 훨씬 더 널리 퍼져 있습니다(특히 데이터 형식을 사용하는 sql_variant
경우). SQL Server 2008 이상 버전에는 특정 경우에 사용되는 메모리 양을 줄이고 전반적으로 더 효율적인 몇 가지 디자인 개선 사항이 있습니다.
해결
오류를 해결하려면 다음 방법 중 하나를 사용합니다.
- 일괄 처리 크기를 줄입니다.
- 매개 변수 형식을 변경합니다. 예를 들어 다른 형식으로 대체
sql_variant
합니다.
USERSTORE_SXC
캐시는 RPC 매개 변수 및 준비된 핸들과 연결된 메모리와 같은 연결 관리 수준 할당에 사용됩니다. 클라이언트가 많은 RPC 호출 일괄 처리가 포함된 요청을 보낼 때 각각과 같은 sql_variant
많은 수의 특정 형식의 매개 변수를 사용할 수 있으므로 이 캐시에서 과도한 할당이 발생하여 사용 가능한 모든 메모리가 소모될 수 있습니다.
또한 애플리케이션을 모니터링하여 준비된 핸들을 적시에 닫아야 합니다. 이러한 핸들을 닫지 않으면 SQL Server가 서버 쪽의 연결된 개체에 대한 메모리를 해제하지 못하게 됩니다.
자세한 정보
이 문서에서 설명하는 문제를 재현하려면 다음 코드를 사용하여 애플리케이션을 만들고 프로그램이 실행될 때 캐시가 USERSTORE_SXC
증가하고 축소되는지 확인합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace RPCBatching
{
class Program
{
static void Main(string[] args)
{
DataTable t = new DataTable();
t.Columns.Add("a", typeof(int));
for(int i=0;i<100000;i++)
t.Rows.Add(1);
// pre-create the table with "CREATE TABLE t (a sql_Variant)" in a database named as test
using (SqlConnection conn = new SqlConnection("server=tcp:localhost; integrated security=true; database=test"))
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(null, conn);
da.InsertCommand = new SqlCommand("INSERT INTO t VALUES (@a)", conn);
da.InsertCommand.Parameters.Add("@a", SqlDbType.Variant, 0, "a");
da.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
da.UpdateBatchSize = 100000;
da.InsertCommand.CommandTimeout = 12000;
da.Update(t);
}
}
}
}