Erreur de dépassement de ligne de 8 Ko lors de la mise à jour de la ligne de taille 5 Ko


8

J'essaie de mettre à jour une table cible qui a également une ligne de taille 5k à une ligne de taille 5k.

Comme il s'agit d'une seule ligne, il est facile de connaître la taille réelle de la ligne:

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

Reproduire

La table n'a pas été modifiée depuis la création. ne vois aucune raison pour laquelle cela devrait échouer. Des idées?


2
Similaire à votre dernière question . Cette erreur se produit lors de la construction d'une table de travail pour un tri trop i.stack.imgur.com/wenSE.png , i.stack.imgur.com/MVyXf.png
Martin Smith

Réponses:


9

Le problème est lié au fait que vous mettez à jour la clé de clustering et que la table de destination possède un schéma de partitionnement 1 . Lorsque SQL Server est invité à mettre à jour un composant de la clé de cluster, il doit effectuer une mise à jour hybride UPDATEet DELETE, ou certaines des lignes sont mises à jour sur place, et d'autres non.

Si vous supprimez l'index cluster de la table de destination, vous verrez que la mise à jour fonctionne.

Le message d'erreur, bien que peut-être un peu trompeur, est précis car la taille de ligne résultante lors de la mise à jour dépasse la longueur maximale.

Je vous suggère d'envisager de changer la structure du tableau pour:

  • ne pas utiliser VARCHAR(MAX)pour toutes ces colonnes. Si vous n'avez pas réellement besoin de 2 Go de caractères dans une seule colonne, pourquoi définir la colonne de cette façon? Définissez la colonne comme étant la taille maximale qui sera rencontrée de façon réaliste.
  • peut-être diviser cette table en plusieurs tables où la taille de ligne maximale résultante est inférieure à 8060 octets. Il semble que vous avez plusieurs groupes logiques de colonnes, comme les V_MAX_xxx, V_64_xxxet les V_512_xxxcolonnes, etc.

Pour simplifier votre repro, vous souhaiterez peut-être éliminer le curseur et effectuer uniquement l'opération DML suivante:

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

La colonne ci-dessus est l'un des composants de la clé de clustering et également de la clé de partitionnement (la mise à jour des autres colonnes de clé CI fonctionne correctement).

Avec l'index clusterisé en place, vous obtenez cette erreur:

Msg 511, niveau 16, état 1, ligne 1

Impossible de créer une ligne de taille 8287 supérieure à la taille de ligne maximale autorisée de 8060.

La déclaration est terminée.

Sans l'index cluster en place, l'instruction réussit.


1 Fait intéressant, si nous éliminons le partitionnement de la repro, nous constatons que la mise à jour réussit, même avec l'index clusterisé en place.


1
Je pense que nous sommes sur la voie d'une solution ici. Fondamentalement, sampletime est le seul que je dois changer, et c'est dans l'index cluster uniquement parce que la table est partitionnée par lui. Une solution sera donc de changer la façon dont la table est partitionnée (ce qui est douloureux, mais possible), puis l'index clusterisé
Yosi Dahari

10

La mise à jour échoue pour des raisons largement similaires à celles que j'ai expliquées en réponse à votre question précédente .

Dans ce cas, étant donné que vous mettez potentiellement à jour plusieurs lignes dans lesquelles une colonne clé d'un index unique est modifiée * , SQL Server crée un plan qui inclut les opérateurs Fractionner, Trier et Réduire pour éviter les violations intermédiaires de clé unique (consultez cet article pour plus de détails) .

L'opérateur de tri ainsi introduit rencontre une ligne intermédiaire (y compris les frais généraux internes) d'une largeur qui dépasse la limite, donc une erreur est générée. L'ajout d'un OPTION (ROBUST PLAN)indice à la requête de mise à jour montre que cela est inévitable:

Msg 8619, niveau 16, état 2, ligne 681
Le processeur de requêtes n'a pas pu produire un plan de requête car une table de travail est requise et sa taille de ligne minimale dépasse le maximum autorisé de 8060 octets. Une raison typique pour laquelle une table de travail est requise est une clause GROUP BY ou ORDER BY dans la requête. Renvoyez votre requête sans le conseil ROBUST PLAN.

Les relations de données source / cible ne sont pas claires pour moi à partir d'un bref aperçu, mais si vous pouvez garantir que chaque opération de mise à jour affectera au plus une ligne, vous pouvez éviter la nécessité du fractionnement / tri / réduction en ajoutant TOP (1)à l'instruction de mise à jour:

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

C'est un peu un hack, cependant. Idéalement, la construction de l'instruction de mise à jour et les index doivent fournir suffisamment d'informations à l'optimiseur pour qu'il puisse voir qu'au plus une ligne sera mise à jour. En particulier, il est recommandé d'écrire des instructions de mise à jour qui sont déterministes .

Compte tenu de la conception étrange et du manque de clarté de la question, je ne vais même pas essayer de déchiffrer les relations entre les données, ou d'interroger et de modifier les changements qui seraient nécessaires pour y parvenir en détail.

* Comme Martin Smith l'a souligné dans un commentaire, ce ne serait pas un problème dans cette situation particulière si la table n'était pas partitionnée. Lorsque la mise à jour définit la clé sur la même valeur déterministe dans chaque ligne, Fractionner / Trier / Réduire n'est pas requis, sauf si la table est également partitionnée sur cette clé. Ainsi, une solution alternative pour cette requête consiste à ne pas partitionner la table au moment de l' échantillonnage .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.