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')
La table n'a pas été modifiée depuis la création. ne vois aucune raison pour laquelle cela devrait échouer. Des idées?
sql-server
sql-server-2012
update
Yosi Dahari
la source
la source
Réponses:
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
UPDATE
etDELETE
, 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:
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.V_MAX_xxx
,V_64_xxx
et lesV_512_xxx
colonnes, etc.Pour simplifier votre repro, vous souhaiterez peut-être éliminer le curseur et effectuer uniquement l'opération DML suivante:
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:
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.
la source
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: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: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 .
la source