AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 102382
Accepted
Yosi Dahari
Yosi Dahari
Asked: 2015-05-22 07:43:37 +0800 CST2015-05-22 07:43:37 +0800 CST 2015-05-22 07:43:37 +0800 CST

Estouro de tamanho de linha de mesclagem no SQL Server - "Não é possível criar uma linha de tamanho .."

  • 772

A tabela de destino na qual estou tentando mesclar os dados tem aproximadamente 660 colunas. O código para a mesclagem:

MERGE TBL_BM_HSD_SUBJECT_AN_1 AS targetTable
USING
        (                
SELECT * 
FROM TBL_BM_HSD_SUBJECT_AN_1_STAGING
WHERE [ibi_bulk_id] in (20150520141627106) and  id in(101659113)
    ) AS sourceTable 
ON (...)
WHEN MATCHED AND ((targetTable.[sampletime] <= sourceTable.[sampletime]))
        THEN UPDATE SET ...
WHEN NOT MATCHED 
        THEN INSERT (...)
    VALUES (...)

A primeira vez que executei isso (ou seja, quando a tabela está vazia), resultou em sucesso e inseri uma linha.

Na segunda vez que executei isso, com o mesmo conjunto de dados, um erro foi retornado:
Não é possível criar uma linha de tamanho 8410 maior que o tamanho máximo permitido de linha de 8060.

Por que a segunda vez que tentei mesclar a mesma linha que já foi inserida resultou em um erro. Se esta linha excedesse o tamanho máximo da linha, esperaria que não fosse possível inseri-la em primeiro lugar.

Então, tentei duas coisas (e consegui!):

  • Removendo a seção "WHEN NOT MATCHED" da declaração de mesclagem
  • Executando uma instrução de atualização com a mesma linha que tentei mesclar

Por que a atualização usando a mesclagem não está sendo bem-sucedida, enquanto a inserção e a atualização direta também?

ATUALIZAR:

Consegui encontrar o tamanho real da linha - 4978. Criei uma nova tabela que possui apenas esta linha e localize o tamanho da linha desta maneira: insira a descrição da imagem aqui

E ainda não vejo algo ultrapassando o limite permitido.

ATUALIZAÇÃO(2):

Reprodução completa

Fez um esforço para que esta reprodução não exija nenhum objeto auxiliar adicional e que os dados sejam (um pouco) ofuscados.

Tentei isso em vários servidores, da versão 2012, e um de 2008, e consegui reproduzir totalmente em todos eles.

sql-server sql-server-2012
  • 1 1 respostas
  • 2327 Views

1 respostas

  • Voted
  1. Best Answer
    Paul White
    2015-08-11T18:19:10+08:002015-08-11T18:19:10+08:00

    Por que a segunda vez que tentei mesclar a mesma linha que já foi inserida resultou em um erro. Se esta linha excedesse o tamanho máximo da linha, esperaria que não fosse possível inseri-la em primeiro lugar.

    Primeiramente, obrigado pelo script de reprodução.

    O problema não é que o SQL Server não pode inserir ou atualizar uma determinada linha visível ao usuário . Como você observou, uma linha que já foi inserida em uma tabela certamente não pode ser fundamentalmente muito grande para o SQL Server manipular.

    O problema ocorre porque a implementação do SQL Server MERGEadiciona informações computadas (como colunas extras) durante as etapas intermediárias no plano de execução. Essas informações extras são necessárias por motivos técnicos, para controlar se cada linha deve resultar em uma inserção, atualização ou exclusão; e também relacionado à maneira como o SQL Server evita genericamente violações de chaves transitórias durante alterações em índices.

    O mecanismo de armazenamento do SQL Server exige que os índices sejam exclusivos (internamente, incluindo qualquer unificador oculto) em todos os momentos - à medida que cada linha é processada - em vez de no início e no final da transação completa. Em cenários mais complexos MERGE, isso requer um Dividir (converter uma atualização em uma exclusão e inserção separadas), Classificar e um Colapso opcional (transformar inserções e atualizações adjacentes na mesma chave em uma atualização). Mais informações .

    Como um aparte, observe que o problema não ocorre se a tabela de destino for um heap (solte o índice clusterizado para ver isso). Não estou recomendando isso como uma correção, apenas mencioná-lo para destacar a conexão entre a manutenção da exclusividade do índice em todos os momentos (agrupado no presente caso) e o Split-Sort-Collapse.

    Em consultas simples , com índices exclusivos adequados e um relacionamento direto entre as linhas de origem e destino (normalmente correspondendo usando uma cláusula que apresenta todas as colunas-chave), o otimizador de consulta pode simplificar muito da lógica genérica, resultando em planos comparativamente simples que não não requer um projeto Split-Sort-Collapse ou Segment-Sequence para verificar se as linhas de destino são tocadas apenas uma vez.MERGEON

    Em consultas complexas MERGE , com lógica mais opaca, o otimizador geralmente é incapaz de aplicar essas simplificações, expondo muito mais da lógica fundamentalmente complexa necessária para o processamento correto (apesar dos bugs do produto, e houve muitos ).

    Sua consulta certamente se qualifica como complexa. A ONcláusula não corresponde às chaves de índice (e eu entendo o porquê), e a 'tabela de origem' é uma junção automática envolvendo uma função de janela de classificação (novamente, com razões):

    MERGE MERGE_REPRO_TARGET AS targetTable
    USING
    (
        SELECT * FROM 
        (
            SELECT 
                *, 
                ROW_NUMBER() OVER (
                    PARTITION BY ww,id, tenant 
                    ORDER BY 
                    (
                        SELECT COUNT(1) 
                        FROM MERGE_REPRO_SOURCE AS targetTable
                        WHERE 
                            targetTable.[ibi_bulk_id] = sourceTable.[ibi_bulk_id] 
                            AND targetTable.[ibi_row_id] <> sourceTable.[ibi_row_id] 
                            AND 
                            (
                                (targetTable.[ww] = sourceTable.[ww]) 
                                AND (targetTable.[id] = sourceTable.[id]) 
                                AND (targetTable.[tenant] = sourceTable.[tenant])
                            ) 
                            AND NOT ((targetTable.[sampletime] <= sourceTable.[sampletime]))
                    ),
                    sourceTable.ibi_row_id DESC
                ) AS idx
            FROM MERGE_REPRO_SOURCE sourceTable 
            WHERE [ibi_bulk_id] in (20150803110418887)
        ) AS bulkData
        where idx = 1
    ) AS sourceTable 
    ON 
        (targetTable.[ww] = sourceTable.[ww]) 
        AND (targetTable.[id] = sourceTable.[id]) 
        AND (targetTable.[tenant] = sourceTable.[tenant])
    ...
    

    Isso resulta em muitas colunas computadas extras, principalmente associadas à Divisão e aos dados necessários quando uma atualização é convertida em um par de inserção/atualização. Essas colunas extras resultam em uma linha intermediária excedendo os 8.060 bytes permitidos em uma classificação anterior - aquela logo após um filtro:

    A classificação do problema

    Observe que o Filtro possui 1.319 colunas (expressões e colunas base) em sua Lista de Saída. Anexar um depurador mostra a pilha de chamadas no ponto em que a exceção fatal é gerada:

    Rastreamento de Pilha

    Observe de passagem que o problema não está no Spool - a exceção é convertida em um aviso sobre o potencial de uma linha ser muito grande.

    Por que a atualização usando a mesclagem não está sendo bem-sucedida, enquanto a inserção e a atualização direta também?

    Uma atualização direta não tem a mesma complexidade interna que o MERGE. É uma operação fundamentalmente mais simples que tende a simplificar e otimizar melhor. A remoção da NOT MATCHEDcláusula também pode remover o suficiente da complexidade para que o erro não seja gerado em alguns casos. Isso não acontece com o repro, no entanto.

    Por fim, meu conselho é evitar MERGEtarefas maiores ou mais complexas. Minha experiência é que as instruções de inserção/atualização/exclusão separadas tendem a otimizar melhor, são mais simples de entender e também costumam ter um desempenho geral melhor, em comparação com MERGE.

    • 11

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve