8k Zeilenüberlauffehler beim Aktualisieren der Zeile der Größe 5k

8

Ich versuche, eine Zieltabelle mit einer Zeile der Größe 5k auf eine Zeile der Größe 5k zu aktualisieren.

Da es sich um eine Zeile handelt, ist die tatsächliche Größe der Zeile leicht zu ermitteln:

select *
from sys.dm_db_index_physical_stats(DB_ID('RODS_HSD_ES'), 
OBJECT_ID(N'TBL_BM_HSD_SUBJECT_AN_148_REPRO'), NULL, NULL, 'DETAILED')

Reproduzieren

Die Tabelle wurde seit der Erstellung nicht geändert. Ich sehe keinen Grund, warum es fehlschlagen sollte. Ideen?

Yosi Dahari
quelle
2
Ähnlich wie bei Ihrer letzten Frage . Dieser Fehler tritt beim Erstellen einer Arbeitstabelle für eine Sortierung auf. I.stack.imgur.com/wenSE.png , i.stack.imgur.com/MVyXf.png
Martin Smith

Antworten:

9

Das Problem hängt damit zusammen, dass Sie den Clustering-Schlüssel aktualisieren und die Zieltabelle zufällig über ein Partitionierungsschema 1 verfügt . Wenn SQL Server aufgefordert wird, eine Komponente des Clustering-Schlüssels zu aktualisieren, muss ein UPDATEund DELETEoder ein Hybrid-Update durchgeführt werden, bei dem einige der Zeilen direkt aktualisiert werden und andere nicht.

Wenn Sie den Clustered-Index aus der Zieltabelle entfernen, funktioniert das Update.

Die Fehlermeldung ist zwar etwas irreführend, aber genau, da die resultierende Zeilengröße während der Aktualisierung die maximale Länge überschreitet.

Ich schlage vor, Sie erwägen, die Struktur der Tabelle zu ändern in:

  • Nicht VARCHAR(MAX)für alle diese Spalten verwenden. Wenn Sie nicht wirklich 2 GB Zeichen in einer einzelnen Spalte benötigen, warum sollten Sie die Spalte dann so definieren? Definieren Sie die Spalte als die maximale Größe, die realistisch angetroffen wird.
  • Teilen Sie diese Tabelle möglicherweise in mehrere Tabellen auf, in denen die resultierende maximale Zeilengröße weniger als 8060 Byte beträgt. Es scheint , dass Sie mehrere logische Gruppen von Spalten haben, wie die V_MAX_xxx, V_64_xxxund V_512_xxxSpalten, usw.

Um Ihre Reproduktion zu vereinfachen, möchten Sie möglicherweise den Cursor entfernen und nur die folgende DML-Operation ausführen:

UPDATE dbo.TBL_BM_HSD_SUBJECT_AN_148_REPRO_TARGET
SET [sampletime]  = '2015-12-29 01:11:26.687';

Die obige Spalte ist eine der Komponenten des Clustering-Schlüssels und auch des Partitionierungsschlüssels (das Aktualisieren anderer CI-Schlüsselspalten funktioniert einwandfrei).

Wenn der Clustered-Index vorhanden ist, wird folgende Fehlermeldung angezeigt:

Nachricht 511, Ebene 16, Status 1, Zeile 1

Es kann keine Zeile mit der Größe 8287 erstellt werden, die größer als die zulässige maximale Zeilengröße von 8060 ist.

Die Anweisung wurde beendet.

Ohne den Clustered-Index ist die Anweisung erfolgreich.


1 Interessanterweise ist das Update erfolgreich, wenn wir die Partitionierung aus dem Repro entfernen, auch wenn der Clustered-Index vorhanden ist.

Max Vernon
quelle
1
Ich denke, wir sind hier auf dem Weg zu einer Lösung. Grundsätzlich ist Sampletime die einzige, die ich ändern muss, und sie befindet sich nur im Clustered-Index, weil die Tabelle von ihr partitioniert wird. Eine Lösung wird also darin bestehen, die Art und Weise zu ändern, in der die Tabelle partitioniert ist (was schmerzhaft, aber möglich ist), und dann den Clustered-Index
Yosi Dahari,
10

Das Update schlägt aus weitgehend ähnlichen Gründen fehl wie die, die ich in Beantwortung Ihrer vorherigen Frage erläutert habe .

In diesem Fall , weil Sie möglicherweise mehrere Zeilen zu aktualisieren , wo eine Schlüsselspalte eines eindeutigen Index wird * geändert , baut SQL Server einen Plan, der Split enthält, sortieren und Schließen Betreiber Zwischen eindeutigen Schlüssel Verletzungen zu vermeiden (siehe diesen Artikel für weitere Details) .

Der so eingeführte Sortieroperator trifft auf eine Zwischenzeile (einschließlich interner Gemeinkosten) mit einer Breite, die den Grenzwert überschreitet, sodass ein Fehler ausgelöst wird. Das Hinzufügen eines OPTION (ROBUST PLAN)Hinweises zur Aktualisierungsabfrage zeigt, dass dies unvermeidbar ist:

Meldung 8619, Ebene 16, Status 2, Zeile 681
Der Abfrageprozessor konnte keinen Abfrageplan erstellen, da eine Arbeitstabelle erforderlich ist und die minimale Zeilengröße die maximal zulässige Größe von 8060 Byte überschreitet. Ein typischer Grund, warum eine Arbeitstabelle erforderlich ist, ist eine GROUP BY- oder ORDER BY-Klausel in der Abfrage. Senden Sie Ihre Anfrage erneut ohne den Hinweis ROBUST PLAN.

Die Beziehungen zwischen Quell- und Zieldaten sind mir auf einen kurzen Blick unklar. Wenn Sie jedoch garantieren können , dass jeder Aktualisierungsvorgang höchstens eine Zeile betrifft, können Sie die Notwendigkeit des Aufteilens / Sortierens / Reduzierens vermeiden, indem Sie TOP (1)der Aktualisierungsanweisung Folgendes hinzufügen :

UPDATE TOP (1) [TBL_BM_HSD_SUBJECT_AN_148_REPRO_TARGET] 
SET ...

Dies ist jedoch ein kleiner Hack. Im Idealfall sollten die Konstruktion und die Indizes der Update-Anweisung dem Optimierer genügend Informationen liefern, damit er sehen kann, dass höchstens eine Zeile aktualisiert wird. Insbesondere wird empfohlen, Aktualisierungsanweisungen zu schreiben, die deterministisch sind .

Angesichts des merkwürdigen Designs und der mangelnden Klarheit der Frage werde ich nicht einmal versuchen, die Datenbeziehungen oder Abfrage- und Indexänderungen zu entschlüsseln, die erforderlich wären, um dies im Detail zu erreichen.

* Wie Martin Smith in einem Kommentar betonte, wäre dies in dieser speziellen Situation kein Problem, wenn die Tabelle nicht partitioniert wäre. Wenn das Update den Schlüssel in jeder Zeile auf denselben deterministischen Wert setzt, ist Teilen / Sortieren / Reduzieren nicht erforderlich, es sei denn, die Tabelle ist auch auf diesem Schlüssel partitioniert. Eine alternative Lösung für diese Abfrage besteht darin, die Tabelle nicht zur Abtastzeit zu partitionieren .

Paul White 9
quelle