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 / 241563
Accepted
George.Palacios
George.Palacios
Asked: 2019-06-28 08:14:19 +0800 CST2019-06-28 08:14:19 +0800 CST 2019-06-28 08:14:19 +0800 CST

ALTER TABLE ... DROP COLUMN é realmente uma operação apenas de metadados?

  • 772

Eu encontrei várias fontes que indicam ALTER TABLE ... DROP COLUMN é uma operação apenas de metadados.

Fonte

Como isso pode ser? Os dados durante uma DROP COLUMN não precisam ser removidos dos índices não clusterizados subjacentes e do índice/heap clusterizado?

Além disso, por que o Microsoft Docs sugere que é uma operação totalmente registrada?

As modificações feitas na tabela são registradas e totalmente recuperáveis. As alterações que afetam todas as linhas em tabelas grandes, como descartar uma coluna ou, em algumas edições do SQL Server, adicionar uma coluna NOT NULL com um valor padrão, podem levar muito tempo para serem concluídas e gerar muitos registros de log . Execute essas instruções ALTER TABLE com o mesmo cuidado que qualquer instrução INSERT, UPDATE ou DELETE que afete muitas linhas.

Como uma pergunta secundária: como o mecanismo acompanha as colunas descartadas se os dados não forem removidos das páginas subjacentes?

sql-server transaction-log
  • 1 1 respostas
  • 2554 Views

1 respostas

  • Voted
  1. Best Answer
    Hannah Vernon
    2019-06-28T11:38:25+08:002019-06-28T11:38:25+08:00

    Há certas circunstâncias em que a eliminação de uma coluna pode ser uma operação somente de metadados. As definições de coluna para qualquer tabela não são incluídas em cada página onde as linhas são armazenadas, as definições de coluna são armazenadas apenas nos metadados do banco de dados, incluindo sys.sysrowsets, sys.sysrscols, etc.

    Ao descartar uma coluna que não é referenciada por nenhum outro objeto, o mecanismo de armazenamento simplesmente marca a definição da coluna como não mais presente, excluindo os detalhes pertinentes de várias tabelas do sistema. A ação de excluir os metadados invalida o cache do procedimento, exigindo uma recompilação sempre que uma consulta fizer referência a essa tabela posteriormente. Como a recompilação retorna apenas as colunas que existem atualmente na tabela, os detalhes da coluna descartada nunca são solicitados; o mecanismo de armazenamento ignora os bytes armazenados em cada página dessa coluna, como se a coluna não existisse mais.

    Quando uma operação DML subsequente ocorre na tabela, as páginas afetadas são regravadas sem os dados da coluna eliminada. Se você reconstruir um índice clusterizado ou um heap, todos os bytes da coluna descartada naturalmente não serão gravados de volta na página no disco. Isso distribui efetivamente a carga de queda da coluna ao longo do tempo, tornando-a menos perceptível.

    Há circunstâncias em que você não pode descartar uma coluna, como quando a coluna é incluída em um índice ou quando você cria manualmente um objeto de estatísticas para a coluna. Eu escrevi uma postagem no blog mostrando o erro que é apresentado ao tentar alterar uma coluna com um objeto de estatísticas criado manualmente. A mesma semântica se aplica ao descartar uma coluna - se a coluna for referenciada por qualquer outro objeto, ela não poderá ser simplesmente descartada. O objeto de referência deve ser alterado primeiro, então a coluna pode ser descartada.

    Isso é bastante fácil de mostrar observando o conteúdo do log de transações depois de descartar uma coluna. O código abaixo cria uma tabela com uma única coluna longa de 8.000 caracteres. Ele adiciona uma linha, depois a descarta e exibe o conteúdo do log de transações aplicável à operação de descarte. Os registros de log mostram modificações em várias tabelas do sistema onde as definições de tabela e coluna são armazenadas. Se os dados da coluna estivessem realmente sendo excluídos das páginas alocadas à tabela, você veria registros de log registrando os dados reais da página; não existem tais registros.

    DROP TABLE IF EXISTS dbo.DropColumnTest;
    GO
    CREATE TABLE dbo.DropColumnTest
    (
        rid int NOT NULL
            CONSTRAINT DropColumnTest_pkc
            PRIMARY KEY CLUSTERED
        , someCol varchar(8000) NOT NULL
    );
    
    INSERT INTO dbo.DropColumnTest (rid, someCol)
    SELECT 1, REPLICATE('Z', 8000);
    GO
    
    DECLARE @startLSN nvarchar(25);
    
    SELECT TOP(1) @startLSN = dl.[Current LSN]
    FROM sys.fn_dblog(NULL, NULL) dl
    ORDER BY dl.[Current LSN] DESC;
    
    DECLARE @a int = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10),      LEFT(@startLSN, 8), 0), 1)
          , @b int = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), SUBSTRING(@startLSN, 10, 8), 0), 1)
          , @c int = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10),     RIGHT(@startLSN, 4), 0), 1);
    
    SELECT @startLSN = CONVERT(varchar(8), @a, 1) 
        + ':' + CONVERT(varchar(8), @b, 1) 
        + ':' + CONVERT(varchar(8), @c, 1)
    
    ALTER TABLE dbo.DropColumnTest DROP COLUMN someCol;
    
    SELECT *
    FROM sys.fn_dblog(@startLSN, NULL)
    
    
    --modify an existing data row 
    SELECT TOP(1) @startLSN = dl.[Current LSN]
    FROM sys.fn_dblog(NULL, NULL) dl
    ORDER BY dl.[Current LSN] DESC;
    
    SET @a = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10),      LEFT(@startLSN, 8), 0), 1);
    SET @b = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10), SUBSTRING(@startLSN, 10, 8), 0), 1);
    SET @c = CONVERT(varbinary(8), '0x' + CONVERT(varchar(10),     RIGHT(@startLSN, 4), 0), 1);
    
    SELECT @startLSN = CONVERT(varchar(8), @a, 1) 
        + ':' + CONVERT(varchar(8), @b, 1) 
        + ':' + CONVERT(varchar(8), @c, 1)
    
    UPDATE dbo.DropColumnTest SET rid = 2;
    
    SELECT *
    FROM sys.fn_dblog(@startLSN, NULL)
    

    (A saída é muito grande para mostrar aqui, e dbfiddle.uk não me permite acessar fn_dblog)

    O primeiro conjunto de saída mostra o log como resultado da instrução DDL eliminando a coluna. O segundo conjunto de saída mostra o log depois de executar a instrução DML em que atualizamos a ridcoluna. No segundo conjunto de resultados, vemos registros de log indicando uma exclusão em dbo.DropColumnTest, seguida por uma inserção em dbo.DropColumnTest. Cada comprimento de registro de log é 8116, indicando que a página real foi atualizada.

    Como você pode ver na saída do fn_dblogcomando no teste acima, toda a operação está totalmente registrada. Isso vale para a recuperação simples, bem como para a recuperação completa. A terminologia "totalmente registrada" pode ser mal interpretada, pois a modificação dos dados não é registrada. Isso não é o que acontece - a modificação é registrada e pode ser totalmente revertida. O log está simplesmente gravando apenas as páginas que foram tocadas e, como nenhuma das páginas de dados da tabela foi registrada pela operação DDL, tanto o DROP COLUMN, quanto qualquer rollback que possa ocorrer acontecerá extremamente rapidamente, independentemente do tamanho da tabela.

    Para science , o código a seguir despejará as páginas de dados da tabela incluída no código acima, usando DBCC PAGE, estilo "3". O estilo "3" indica que queremos o cabeçalho da página mais a interpretação detalhada por linha . O código usa um cursor para exibir os detalhes de cada página na tabela, portanto, você pode ter certeza de não executar isso em uma tabela grande.

    DBCC TRACEON(3604); --directs out from DBCC commands to the console, instead of the error log
    DECLARE @dbid int = DB_ID();
    DECLARE @fileid int;
    DECLARE @pageid int;
    DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
    FOR
    SELECT dpa.allocated_page_file_id
        , dpa.allocated_page_page_id
    FROM sys.schemas s  
        INNER JOIN sys.objects o ON o.schema_id = s.schema_id
    CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), o.object_id, NULL, NULL, 'DETAILED') dpa
    WHERE o.name = N'DropColumnTest'
        AND s.name = N'dbo'
        AND dpa.page_type_desc = N'DATA_PAGE';
    OPEN cur;
    FETCH NEXT FROM cur INTO @fileid, @pageid;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        DBCC PAGE (@dbid, @fileid, @pageid, 3);
        FETCH NEXT FROM cur INTO @fileid, @pageid;
    END
    CLOSE cur;
    DEALLOCATE cur;
    DBCC TRACEOFF(3604);
    

    Observando a saída da primeira página da minha demonstração (depois que a coluna é descartada, mas antes que a coluna seja atualizada), vejo isso:

    PÁGINA: (1:100104)
    
    
    AMORTECEDOR:
    
    
    BUF @0x0000021793E42040
    
    bpage = 0x000002175A7A0000 bhash = 0x0000000000000000 bpageno = (1:100104)
    bdbid = 10 breferences = 1 bcputicks = 0
    bsampleCount = 0 bUse1 = 13760 bstat = 0x10b
    blog = 0x212121cc bnext = 0x0000000000000000 bDirtyContext = 0x000002175004B640
    bstat2 = 0x0                        
    
    CABEÇALHO DA PÁGINA:
    
    
    Página @0x000002175A7A0000
    
    m_pageId = (1:100104) m_headerVersion = 1 m_type = 1
    m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0xc000
    m_objId (AllocUnitId.idObj) = 300 m_indexId (AllocUnitId.idInd) = 256
    Metadados: AllocUnitId = 72057594057588736                                
    Metadados: PartitionId = 72057594051756032 Metadados: IndexId = 1
    Metadados: ObjectId = 174623665 m_prevPage = (0:0) m_nextPage = (0:0)
    pminlen = 8 m_slotCnt = 1 m_freeCnt = 79
    m_freeData = 8111 m_reservedCnt = 0 m_lsn = (616:14191:25)
    m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
    m_tornBits = 0 ID de fragmentação de banco de dados = 1                      
    
    Status de alocação
    
    GAM (1:2) = ALOCADO SGAM (1:3) = NÃO ALOCADO          
    PFS (1:97056) = 0x40 ALOCADO 0_PCT_FULL DIFF (1:6) = ALTERADO
    ML (1:7) = NÃO MIN_LOGGED           
    
    Slot 0 Offset 0x60 Comprimento 8015
    
    Tipo de registro = PRIMARY_RECORD Atributos de registro = NULL_BITMAP VARIABLE_COLUMNS
    Tamanho do registro = 8015                  
    Despejo de memória @0x000000B75227A060
    
    0000000000000000: 30000800 01000000 02000001 004f1f5a 5a5a5a5a 0............O.ZZZZZ
    0000000000000014: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZ
    .
    .
    .
    0000000000001F2C: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZ
    0000000000001F40: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a ZZZZZZZZZZZZZZZ
    
    Slot 0 Coluna 1 Offset 0x4 Comprimento 4 Comprimento (físico) 4
    
    livrar = 1                             
    
    Slot 0 Coluna 67108865 Offset 0xf Comprimento 0 Comprimento (físico) 8000
    
    RETIRADO = NULO                      
    
    Slot 0 Offset 0x0 Comprimento 0 Comprimento (físico) 0
    
    KeyHashValue = (8194443284a0)       
    

    Eu removi a maior parte do despejo de página bruta da saída mostrada acima para brevidade. No final da saída, você verá isso para a ridcoluna:

    Slot 0 Coluna 1 Offset 0x4 Comprimento 4 Comprimento (físico) 4
    
    livrar = 1                             
    

    A última linha acima, rid = 1, retorna o nome da coluna e o valor atual armazenado na coluna na página.

    A seguir, você verá isso:

    Slot 0 Coluna 67108865 Offset 0xf Comprimento 0 Comprimento (físico) 8000
    
    RETIRADO = NULO                      
    

    A saída mostra que o Slot 0 contém uma coluna excluída, em virtude do DELETEDtexto onde normalmente estaria o nome da coluna. O valor da coluna é retornado como NULLdesde que a coluna foi excluída. No entanto, como você pode ver nos dados brutos, o valor de 8.000 caracteres, REPLICATE('Z', 8000), para essa coluna ainda existe na página. Esta é uma amostra dessa parte da saída DBCC PAGE:

    0000000000001EDC: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZ
    0000000000001EF0: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZ
    0000000000001F04: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZ
    0000000000001F18: 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZZZZZ
    • 16

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