Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В статье рассматривается ошибка 701, которая может возникать при выполнении большого пакета операций в SQL Server. Сведения о других причинах ошибки 701 см. в MSSQLSERVER_701.
Исходная версия продукта: SQL Server
Исходный номер базы знаний: 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.
Если вы проверяете выходные данные DBCC MEMORYSTATUS , которые автоматически регистрируются в журнал ошибок в сообщениях об ошибках 701, вы найдете такие записи, как следующие:
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_clerks динамического административного представления (DMV) во время выполнения single_pages_kb
пакета столбец USERSTORE_SXC
кэша показывает непрерывный рост за период, который создает ошибку 701.
Пример приложения, которое потенциально может привести к такому поведению, см . дополнительные сведения.
Причина
Объем памяти, выделенной для хранения запроса в SQL Server, зависит от:
- Размер пакета (количество RPCs на запрос).
- Число параметров.
- Тип параметров.
Для определенных типов параметров (например, 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);
}
}
}
}