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 / 208530
Accepted
Elaskanator
Elaskanator
Asked: 2018-06-02 12:07:33 +0800 CST2018-06-02 12:07:33 +0800 CST 2018-06-02 12:07:33 +0800 CST

SQL Server - Adicionando coluna não anulável à tabela existente - Publicação SSDT

  • 772

Devido à lógica de negócios, precisamos de uma nova coluna em uma tabela que seja essencial para garantir que ela seja sempre preenchida. Portanto, deve ser adicionado à tabela como NOT NULL. Ao contrário das perguntas anteriores que explicam como fazer isso manualmente , isso precisa ser gerenciado pela publicação do SSDT.

Eu tenho batido minha cabeça contra a parede por um tempo por causa dessa tarefa que parece simples devido a algumas realizações:

  1. Um valor padrão não é apropriado e não pode ser uma coluna computada. Talvez seja uma coluna de chave estrangeira, mas para outras não podemos usar um valor falso como 0 ou -1 porque esses valores podem ter significado (por exemplo, dados numéricos).
  2. Adicionar a coluna em um script de pré-implantação falhará na publicação quando tentar criar automaticamente a mesma coluna, uma segunda vez (mesmo que o script de pré-implantação seja escrito para ser idempotente) (este é realmente agravante, pois posso de outra forma pense em uma solução fácil)
  3. A alteração da coluna para NOT NULL em um script pós-implantação será revertida toda vez que ocorrer a atualização do esquema SSDT (portanto, no mínimo, nossa base de código não corresponderá entre o controle de origem e o que está realmente no servidor)
  4. Adicionar a coluna como anulável agora com a intenção de mudar para NOT NULL no futuro não funciona em várias ramificações/bifurcações no controle de origem, pois os sistemas de destino não necessariamente terão a tabela no mesmo estado na próxima vez que forem atualizados ( não que esta seja uma boa abordagem de qualquer maneira IMO)

A abordagem que ouvi de outras pessoas é atualizar diretamente a definição da tabela (para que a atualização do esquema seja consistente), escrever um script de pré-implantação que mova todo o conteúdo da tabela para uma tabela temporária com a nova lógica de preenchimento de coluna incluída e, em seguida, mova as linhas de volta em um script pós-implantação. Isso parece arriscado como o inferno, e ainda irrita o Publish Preview quando detecta que uma coluna NOT NULL está sendo adicionada a uma tabela com dados existentes (já que a validação é executada antes do script de pré-implantação).

Como devo adicionar uma nova coluna não anulável sem arriscar dados órfãos ou mover dados para frente e para trás em cada publicação com longos scripts de migração que são inerentemente arriscados?

Obrigado.

sql-server scripting
  • 1 1 respostas
  • 7115 Views

1 respostas

  • Voted
  1. Best Answer
    Josh Darnell
    2018-06-13T10:56:22+08:002018-06-13T10:56:22+08:00

    Vou compartilhar como eu fiz isso no passado. Ele foi projetado para resolver a limitação específica de scripts de pré-implantação que você chama em seu segundo ponto:

    Adicionar a coluna em um script de pré-implantação falhará na publicação quando tentar criar automaticamente a mesma coluna, uma segunda vez (mesmo que o script de pré-implantação seja escrito para ser idempotente)

    Por que os scripts de pré-implantação não funcionam para isso

    Quando você implanta um projeto SSDT, a maneira como ele une as coisas é assim (um pouco simplificada, mas em geral):

    1. Faça a "comparação de esquema" entre a fonte (arquivo dacpac) e o destino (banco de dados)
    2. Gere um script de implantação com base nos resultados dessa comparação
    3. Processe qualquer script de pré-implantação no dacpac (fazendo substituição de token, etc.) e insira o conteúdo no início do script de implantação
    4. Faça o mesmo para scripts pós-implantação, anexando ao final do script de implantação

    Quando existe uma nova coluna no dacpac e não no banco de dados de destino, a etapa 2 gerará o código para adicionar essa coluna. Portanto, se o script de pré-implantação adicionar essa coluna, a parte principal do script falhará (porque assume que a coluna não existe, com base nos resultados da comparação de esquema na etapa 1)

    Solução: script pré-SSDT

    Martin Smith mencionou essa opção em um comentário e é a solução que funcionou melhor para mim até agora:

    Usamos scripts de pré-modelo em nosso pipeline de distribuição. Isso não é algo que faz parte do SSDT, mas uma etapa que é executada antes da publicação do dacfx. Portanto, neste caso, o script do premodel poderia adicionar a coluna com os valores desejados e torná-la não nula e, no momento da publicação, ela já está no estado esperado pelo SSDT, portanto, não tem nada a ver. Ainda estou para encontrar muita utilidade para scripts de pré-implantação. – Martin Smith 01 de junho às 21:45

    Os passos para implementar esta solução em geral são:

    1. Crie um script no projeto SSDT para manter seu código T-SQL "pré-SSDT"
      • Dependendo de como seu processo de implantação funciona, o código nesses arquivos provavelmente deve ser idempotente
    2. Certifique-se de definir este script como "Build Action=None" e "Copy to Output Directory=Copy Always"
      • a opção "copiar sempre" é especialmente importante, pois o processo de implantação precisa encontrar esse script em seus artefatos de implantação
    3. Em seu processo de implantação, localize e execute este script (ou scripts) antes que ocorra a comparação do esquema SSDT
    4. Uma vez que o script foi executado com sucesso, você pode envolver DacServices / DacFx / qualquer coisa para completar sua implantação como de costume

    No final, isso permite que você adicione a coluna usando qualquer código personalizado que desejar, preenchido usando lógica de negócios complexa, no script pré-SSDT.

    Você também adiciona a definição de coluna no projeto SSDT (para que o controle de origem ainda corresponda ao estado real do banco de dados). Mas quando a comparação de esquema é executada, ela não vê alterações relacionadas a essa coluna (porque você já a implantou).

    Outros usos do pré-SSDT

    Muitas vezes, ao testar implantações, vejo que o SSDT executa uma operação de "reconstrução de tabela"* quando é completamente desnecessária. É aqui que uma nova tabela é criada com o esquema atualizado, todos os dados são copiados para essa tabela, a tabela antiga é eliminada e a nova tabela é renomeada para substituir a tabela antiga.

    Isso pode levar ao crescimento massivo do arquivo de log de transações e outros problemas se a tabela for grande. Se eu perceber que uma alteração de esquema está causando isso, eu mesmo farei a alteração no pré-SSDT (que geralmente é uma ALTER TABLEinstrução simples) e evitarei a reconstrução da tabela.

    isso é uma boa ideia?

    Eu penso que sim. Se você ler Criticando duas abordagens diferentes para entregar bancos de dados: Migrations vs state por Alex Yates, isso é essencialmente combinar um pouco as duas abordagens. O SSDT é baseado em estado, mas incorporamos uma etapa de migração (antes do SSDT) ​​para lidar com alguns dos cenários mais complexos com os quais o SSDT simplesmente não tem como lidar de maneira geral.

    Ao fazer algumas pesquisas enquanto escrevia esta resposta, essa é realmente uma abordagem muito comum discutida na comunidade de usuários do SSDT quando você sabe o que procurar. Eu vi isso chamado:

    • pré-comparar
    • pré-modelo
    • pré-DAC
    • pré-SSDT

    Etc. Aqui está um ótimo artigo que cobre muitos dos pontos que mencionei acima:

    Scripts de pré-comparação e pré-implantação para SSDT

    E um do Red Gate (na seção #4 – Mudando do tipo de sistema para o tipo definido pelo usuário ) que também se refere a isso como pré-comparação:

    Como corrigir dez problemas de implantação SSDT, com ou sem ReadyRoll

    Então, qual é o objetivo dos scripts de pré-implantação?

    Martin aponta que ele não encontrou " muito uso para scripts de pré-implantação ". Eu tendo a me sentir da mesma maneira. Mas há cenários em que eles podem ser úteis.

    Um exemplo que um colega de trabalho apontou para mim foi armazenar alguns dados em uma tabela temporária para serem usados ​​no script de pós-implantação (digamos que você esteja movendo uma coluna de uma tabela para outra).


    *A reconstrução da tabela se parece com isso, o que é horrível, certo?

    GO
    PRINT N'Starting rebuilding table [dbo].[MyTable]...';
    
    
    GO
    BEGIN TRANSACTION;
    
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    
    SET XACT_ABORT ON;
    
    CREATE TABLE [dbo].[tmp_ms_xx_MyTable] (
        [Id] BIGINT IDENTITY (1, 1) NOT NULL,
        -- etc, other columns
    );
    
    IF EXISTS (SELECT TOP 1 1 
               FROM   [dbo].[MyTable])
        BEGIN
            SET IDENTITY_INSERT [dbo].[tmp_ms_xx_MyTable] ON;
            INSERT INTO [dbo].[tmp_ms_xx_MyTable] ([Id], ...)
            SELECT   [Id],
                     -- etc, other columns
            FROM     [dbo].[MyTable]
            ORDER BY [Id] ASC;
            SET IDENTITY_INSERT [dbo].[tmp_ms_xx_MyTable] OFF;
        END
    
    DROP TABLE [dbo].[MyTable];
    
    EXECUTE sp_rename N'[dbo].[tmp_ms_xx_MyTable]', N'MyTable';
    
    COMMIT TRANSACTION;
    
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    
    • 18

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