Erro de estouro de linha de 8k ao atualizar linha de tamanho 5k

8

Estou tentando atualizar uma tabela de destino que tem uma linha de tamanho 5k para uma linha de tamanho 5k também.

Como é uma linha, é fácil saber o tamanho real da linha:

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

Reproduzir

A tabela não foi alterada desde a criação. não vejo nenhuma razão para que falhe. Ideias?

Yosi Dahari
fonte
2
Semelhante à sua última pergunta . Este erro está ao criar uma tabela de trabalho para uma classificação também i.stack.imgur.com/wenSE.png , i.stack.imgur.com/MVyXf.png
Martin Smith

Respostas:

9

O problema está relacionado ao fato de você estar atualizando a chave de cluster e a tabela de destino possui um esquema de particionamento 1 . Quando o SQL Server é solicitado a atualizar qualquer componente da chave de cluster, ele deve executar uma atualização híbrida UPDATEe DELETE/ ou onde algumas das linhas são atualizadas no local e outras não.

Se você remover o índice clusterizado da tabela de destino, verá a atualização funcionando.

A mensagem de erro, embora talvez um pouco enganadora, é precisa, pois o tamanho da linha resultante durante a atualização excede o tamanho máximo.

Sugiro que você considere alterar a estrutura da tabela para:

  • não use VARCHAR(MAX)para todas essas colunas. Se você realmente não precisa de 2 GB de caracteres em uma única coluna, por que definir a coluna dessa maneira? Defina a coluna como o tamanho máximo que será encontrado realisticamente.
  • talvez divida esta tabela em várias tabelas em que o tamanho máximo da linha resultante seja menor que 8060 bytes. Parece que você tem vários clusters lógicos de colunas, como as V_MAX_xxx, V_64_xxxe V_512_xxxcolunas, etc.

Para simplificar sua reprodução, convém eliminar o cursor e fazer apenas a seguinte operação DML:

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

A coluna acima é um dos componentes da chave de cluster e também a chave de particionamento (a atualização de outras colunas de chave de IC funciona bem).

Com o índice clusterizado no lugar, você recebe este erro:

Msg 511, Nível 16, Estado 1, Linha 1

Não é possível criar uma linha de tamanho 8287 que seja maior que o tamanho máximo permitido da linha de 8060.

A instrução foi encerrada.

Sem o índice clusterizado no lugar, a instrução é bem-sucedida.


1 Curiosamente, se eliminarmos o particionamento da reprodução, verificamos que a atualização foi bem-sucedida, mesmo com o índice clusterizado.

Max Vernon
fonte
11
Acho que estamos no caminho de uma solução aqui. Basicamente, o sampletime é o único que tenho que alterar e é o índice agrupado apenas porque a tabela é particionada por ele. Assim, uma solução será a de mudar a maneira como a tabela é particionado (o qual é dolorosa, mas possível), e, em seguida, o índice de cluster
Yosi Dahari
10

A atualização falha por razões muito semelhantes às que expliquei em resposta à sua pergunta anterior .

Nesse caso, como você está potencialmente atualizando várias linhas nas quais uma coluna de chave de um índice exclusivo é alterada * , o SQL Server cria um plano que inclui operadores Split, Sort e Collapse para evitar violações intermediárias de chave exclusiva (consulte este artigo para obter detalhes) .

O operador Sort, assim introduzido, encontra uma linha intermediária (incluindo as despesas gerais) de uma largura que excede o limite; portanto, é gerado um erro. Adicionar uma OPTION (ROBUST PLAN)dica à consulta de atualização mostra que isso é inevitável:

Msg 8619, Nível 16, Estado 2, Linha 681
O processador de consultas não pôde produzir um plano de consultas porque é necessária uma mesa de trabalho e seu tamanho mínimo de linha excede o máximo permitido de 8060 bytes. Um motivo típico pelo qual uma tabela de trabalho é necessária é uma cláusula GROUP BY ou ORDER BY na consulta. Reenvie sua consulta sem a dica ROBUST PLAN.

Os relacionamentos de dados de origem / destino não são claros para mim em uma breve olhada, mas se você puder garantir que cada operação de atualização afetará no máximo uma linha, poderá evitar a necessidade de Dividir / Classificar / Recolher adicionando TOP (1)à instrução de atualização:

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

Isso é um pouco complicado, no entanto. Idealmente, a construção da instrução de atualização e os índices devem fornecer informações suficientes para o otimizador, para que ele possa ver que no máximo uma linha será atualizada. Em particular, é uma prática recomendada escrever instruções de atualização determinísticas .

Dado o design estranho e a falta de clareza na pergunta, não vou nem tentar decifrar os relacionamentos de dados, nem as alterações de consulta e índice que seriam necessárias para conseguir isso em detalhes.

* Como Martin Smith apontou em um comentário, isso não seria um problema nessa situação específica se a tabela não fosse particionada. Onde a atualização define a chave com o mesmo valor determinístico em todas as linhas, Dividir / Classificar / Recolher não é necessário, a menos que a tabela também seja particionada nessa chave. Portanto, uma solução alternativa para essa consulta é não particionar a tabela no sampletime .

Paul White 9
fonte