Freigeben über


SQL Server meldet 701: "Es ist nicht genügend Arbeitsspeicher vorhanden, um diese Abfrage auszuführen", wenn große Batches ausgeführt werden

In diesem Artikel wird der Fehler 701 erläutert, der auftreten kann, wenn Sie einen großen Batch von Vorgängen in SQL Server ausführen. Weitere Ursachen von 701-Fehlern finden Sie unter MSSQLSERVER_701.

Ursprüngliche Produktversion: SQL Server
Ursprüngliche KB-Nummer: 2001221

Problembeschreibung

Wenn Sie in SQL Server einen großen Batch von Remoteprozeduraufrufen (RPC) ausführen (z. B. Zehntausende von Einfügungen in einem einzelnen Batch), schlägt der Vorgang möglicherweise mit den folgenden Fehlern fehl, die im SQL Server-Fehlerprotokoll gemeldet werden:

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.

Wenn Sie die Ausgabe von DBCC MEMORYSTATUS überprüfen, die automatisch bei 701 Fehlermeldungen beim Fehlerprotokoll protokolliert wird, finden Sie Einträge wie die folgenden:

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. 

Notiz

Beachten Sie die großen Zuordnungen für den Cache USERSTORE_SXC.

Wenn Sie außerdem die sys.dm_os_memory_clerks dynamische Verwaltungsansicht (DYNAMIC Management View, DMV) abfragen, während der Batch ausgeführt wird, zeigt die single_pages_kb Spalte für den USERSTORE_SXC Cache ein kontinuierliches Wachstum über einen Zeitraum an, der den Fehler 701 generiert.

Ein Beispiel für eine Anwendung, die dieses Verhalten möglicherweise aufweisen könnte, finden Sie unter "Weitere Informationen".

Ursache

Die Zum Speichern einer Anforderung in SQL Server zugewiesene Speichermenge hängt von folgenden Faktoren ab:

  • Die Batchgröße (Anzahl der RPCs pro Anforderung).
  • Die Anzahl der Parameter.
  • Der Typ der Parameter.

Bei bestimmten Parametertypen (z . B. sql_variant) kann SQL Server die Anforderungen im Arbeitsspeicher potenziell ineffizient speichern. Wenn ein Client eine große Anzahl von Anforderungen sendet, die diese Parametertypen verwenden, können mehrere RPCs in einer Anforderung gesendet werden. In diesem Szenario sammelt der Server die gesamte Anforderung im Arbeitsspeicher, bevor sie ausgeführt wird. Dies könnte möglicherweise zu dem 701-Fehler führen, der in Den Symptomen behandelt wird.

Das Problem ist in älteren Versionen von SQL Server weit verbreiteter (insbesondere bei Verwendung des sql_variant Datentyps). SQL Server 2008 und höhere Versionen verfügen über einige Entwurfsverbesserungen, die die Menge des verwendeten Arbeitsspeichers in bestimmten Fällen reduzieren und insgesamt effizienter sind.

Lösung

Verwenden Sie zum Beheben des Fehlers eine der folgenden Methoden:

  • Reduzieren Sie die Batchgrößen.
  • Parametertypen ändern. Ersetzen Sie sql_variant z. B. durch andere Typen.

Der USERSTORE_SXC Cache wird für Zuordnungen auf Verbindungsverwaltungsebene verwendet, z. B. RPC-Parameter und den Arbeitsspeicher, der mit vorbereiteten Handles verknüpft ist. Wenn ein Client eine Anforderung sendet, die einen großen Batch an RPC-Aufrufen enthält, kann jeder eine große Anzahl bestimmter Parametertypen verwenden, z sql_variant. B. zu übermäßigen Zuordnungen aus diesem Cache, wodurch der gesamte verfügbare Speicher erschöpft wird.

Die Anwendung sollte auch überwacht werden, um sicherzustellen, dass Sie vorbereitete Handles zeitnah schließen. Wenn Sie diese Handles nicht schließen, wird verhindert, dass SQL Server Arbeitsspeicher für die zugehörigen Objekte auf serverseitiger Seite freigibt.

Weitere Informationen

Um das in diesem Artikel beschriebene Problem zu reproduzieren, erstellen Sie eine Anwendung mithilfe des folgenden Codes, und beachten Sie, dass der USERSTORE_SXC Cache wächst und verkleinern wird, während das Programm ausgeführt wird.

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);
            }
        }
    }
}