Estoy tratando de actualizar una tabla de destino que tiene una fila de tamaño 5k a una fila de tamaño 5k también.
Como es una fila, es fácil saber el tamaño real de la fila:
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 tabla no fue alterada desde la creación. No veo ninguna razón por la que debería fallar. Ideas?
sql-server
sql-server-2012
update
Yosi Dahari
fuente
fuente
Respuestas:
El problema está relacionado con el hecho de que está actualizando la clave de agrupación y la tabla de destino tiene un esquema de partición 1 . Cuando se solicita a SQL Server que actualice cualquier componente de la clave de agrupación, debe realizar una actualización híbrida
UPDATE
yDELETE
/ o híbrida donde algunas de las filas se actualizan in situ y otras no.Si elimina el índice agrupado de la tabla de destino, verá que la actualización funciona.
El mensaje de error, aunque quizás sea un poco engañoso, es preciso ya que el tamaño de la fila resultante durante la actualización excede la longitud máxima.
Le sugiero que considere cambiar la estructura de la tabla a:
VARCHAR(MAX)
para todas esas columnas. Si en realidad no necesita 2 GB de caracteres en una sola columna, ¿por qué definir la columna de esa manera? Defina la columna como el tamaño máximo que se encontrará de manera realista.V_MAX_xxx
,V_64_xxx
yV_512_xxx
columnas, etc.Para simplificar su repro, es posible que desee eliminar el cursor y solo realizar la siguiente operación DML:
La columna anterior es uno de los componentes de la clave de agrupación y también la clave de partición (la actualización de otras columnas de clave CI funciona bien).
Con el índice agrupado en su lugar, obtiene este error:
Sin el índice agrupado en su lugar, la declaración tiene éxito.
1 Curiosamente, si eliminamos la partición de la reproducción, encontramos que la actualización se realiza correctamente, incluso con el índice agrupado en su lugar.
fuente
La actualización falla por razones muy similares a las que expliqué en respuesta a su pregunta anterior .
En este caso, debido a que potencialmente está actualizando varias filas donde se cambia una columna clave de un índice único * , SQL Server crea un plan que incluye operadores de división, clasificación y colapso para evitar violaciones de clave únicas intermedias (consulte este artículo para más detalles) .
El operador de clasificación así introducido encuentra una fila intermedia (incluidos los gastos generales internos) de un ancho que excede el límite, por lo que se genera un error. Agregar una
OPTION (ROBUST PLAN)
pista a la consulta de actualización muestra que esto es inevitable:Las relaciones de datos de origen / destino no están claras para mí desde un breve vistazo, pero si puede garantizar que cada operación de actualización afectará a lo más una fila, puede evitar la necesidad de dividir / ordenar / contraer agregando
TOP (1)
a la declaración de actualización:Sin embargo, esto es un poco hack. Idealmente, la construcción de la declaración de actualización y los índices deberían proporcionar suficiente información al optimizador para que pueda ver que, como máximo, se actualizará una fila. En particular, es una buena práctica escribir declaraciones de actualización que sean deterministas .
Dado el diseño extraño y la falta de claridad en la pregunta, ni siquiera voy a tratar de descifrar las relaciones de datos, o los cambios de consulta e índice que serían necesarios para lograr esto en detalle.
* Como Martin Smith señaló en un comentario, esto no sería un problema en esta situación particular si la tabla no estuviera particionada. Cuando la actualización establece la clave en el mismo valor determinista en cada fila, no es necesario dividir / ordenar / contraer, a menos que la tabla también esté particionada en esa clave. Entonces, una solución alternativa para esta consulta es no particionar la tabla en tiempo de muestreo .
fuente