Errore di overflow della riga 8k durante l'aggiornamento della riga di dimensioni 5k


8

Sto cercando di aggiornare una tabella di destinazione che ha anche una riga di dimensioni 5k con una riga di dimensioni 5k.

Poiché è una riga è facile conoscere la dimensione effettiva della riga:

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')

Riprodurre

La tabella non è stata modificata dalla creazione. non vedo alcun motivo per cui dovrebbe fallire. Idee?


2
Simile alla tua ultima domanda . Questo errore si verifica anche durante la costruzione di un piano di lavoro per una sorta i.stack.imgur.com/wenSE.png , i.stack.imgur.com/MVyXf.png
Martin Smith

Risposte:


9

Il problema è legato al fatto che si sta aggiornando la chiave di clustering e la tabella di destinazione presenta uno schema di partizionamento 1 . Quando viene richiesto a SQL Server di aggiornare qualsiasi componente della chiave di clustering, è necessario eseguire un aggiornamento ibrido UPDATEe DELETE, o in cui alcune delle righe vengono aggiornate sul posto e altre no.

Se rimuovi l'indice cluster dalla tabella di destinazione, vedrai che l'aggiornamento funziona.

Il messaggio di errore, sebbene forse un po 'fuorviante, è accurato poiché la dimensione della riga risultante durante l'aggiornamento supera la lunghezza massima.

Ti suggerisco di considerare di modificare la struttura della tabella in:

  • non utilizzare VARCHAR(MAX)per tutte quelle colonne. Se in realtà non hai bisogno di 2 GB di caratteri in una singola colonna, perché definire la colonna in quel modo? Definire la colonna per la dimensione massima che verrà rilevata realisticamente.
  • forse dividere questa tabella in più tabelle in cui la dimensione massima della riga risultante è inferiore a 8060 byte. Sembra si dispone di diversi gruppi logici di colonne, come le V_MAX_xxx, V_64_xxxe V_512_xxxcolonne, ecc

Per semplificare la riproduzione, potresti voler eliminare il cursore e eseguire solo le seguenti operazioni DML:

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

La colonna sopra è uno dei componenti della chiave di clustering e anche la chiave di partizionamento (l'aggiornamento di altre colonne di chiavi CI funziona correttamente).

Con l'indice cluster attivo, viene visualizzato questo errore:

Messaggio 511, livello 16, stato 1, riga 1

Impossibile creare una riga di dimensioni 8287 superiore alla dimensione massima consentita di 8060.

La dichiarazione è stata chiusa.

Senza l'indice cluster in atto, l'istruzione ha esito positivo.


1 È interessante notare che se eliminiamo il partizionamento dalla riproduzione, troviamo che l'aggiornamento ha esito positivo, anche con l'indice cluster in atto.


1
Penso che siamo sulla strada di una soluzione qui. Fondamentalmente, sampletime è l'unico che devo cambiare ed è l'indice cluster solo perché la tabella è partizionata da esso. Quindi una soluzione sarà quella di cambiare il modo in cui la tabella è partizionata (il che è doloroso, ma possibile), e quindi l'indice cluster
Yosi Dahari,

10

L'aggiornamento fallisce per motivi sostanzialmente simili a quelli che ho spiegato in risposta alla tua domanda precedente .

In questo caso, poiché si sta potenzialmente aggiornando più righe in cui viene modificata una colonna chiave di un indice univoco * , SQL Server crea un piano che include gli operatori Dividi, Ordina e Comprimi per evitare violazioni intermedie della chiave univoca (vedere questo articolo per i dettagli) .

L'operatore di ordinamento così introdotto incontra una riga intermedia (comprese le spese generali interne) di una larghezza che supera il limite, quindi viene generato un errore. L'aggiunta di un OPTION (ROBUST PLAN)suggerimento alla query di aggiornamento indica che ciò è inevitabile:

Messaggio 8619, livello 16, stato 2, riga 681
Il processore di query non è stato in grado di produrre un piano di query perché è richiesto un piano di lavoro e la sua dimensione minima della riga supera il massimo consentito di 8060 byte. Un motivo tipico per cui è richiesto un worktable è una clausola GROUP BY o ORDER BY nella query. Reinvia la tua richiesta senza il suggerimento PIANO ROBUSTO.

Le relazioni con i dati di origine / destinazione non mi sono chiare da una breve occhiata, ma se puoi garantire che ogni operazione di aggiornamento influirà al massimo su una riga, puoi evitare la necessità di dividere / ordinare / comprimere aggiungendo TOP (1)all'istruzione di aggiornamento:

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

Questo è un po 'un trucco, però. Idealmente, la costruzione dell'istruzione di aggiornamento e gli indici dovrebbero fornire informazioni sufficienti all'ottimizzatore in modo che possa vedere che verrà aggiornata al massimo una riga. In particolare, è consigliabile scrivere istruzioni di aggiornamento deterministiche .

Data la strana progettazione e la mancanza di chiarezza nella domanda, non ho nemmeno intenzione di provare a decifrare le relazioni dei dati, o le query e le modifiche dell'indice che sarebbero necessarie per raggiungere questo obiettivo in dettaglio.

* Come ha sottolineato Martin Smith in un commento, questo non sarebbe un problema in questa situazione particolare se la tabella non fosse partizionata. Laddove l'aggiornamento imposta la chiave sullo stesso valore deterministico in ogni riga, non è richiesto Dividi / Ordina / Comprimi, a meno che la tabella non sia anche partizionata su quella chiave. Pertanto, una soluzione alternativa per questa query è quella di non partizionare la tabella in sampletime .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.