Preciso migrar um banco de dados SQL Server 2017 local para um banco de dados SQL do Azure e estou enfrentando alguns desafios, pois há algumas limitações a serem enfrentadas.
Em particular, como um banco de dados SQL do Azure funciona apenas no horário UTC (sem fusos horários) e precisamos do horário local, temos que alterar o uso de todos os GETDATE()
lugares no banco de dados, o que provou ser mais trabalhoso do que eu previa.
Eu criei uma função definida pelo usuário para obter a hora local que funciona corretamente para o meu fuso horário:
CREATE FUNCTION [dbo].[getlocaldate]()
RETURNS datetime
AS
BEGIN
DECLARE @D datetimeoffset;
SET @D = CONVERT(datetimeoffset, SYSDATETIMEOFFSET()) AT TIME ZONE 'Pacific SA Standard Time';
RETURN(CONVERT(datetime,@D));
END
O problema com o qual estou tendo problemas é realmente alterar GETDATE()
essa função em todas as visualizações, procedimentos armazenados, colunas computadas, valores padrão, outras restrições etc.
Qual seria a melhor maneira de implementar essa mudança?
Estamos na visualização pública de instâncias gerenciadas . Ele ainda tem o mesmo problema com GETDATE()
, portanto, não ajuda com esse problema. A migração para o Azure é um requisito. Este banco de dados é usado (e será usado) sempre neste fuso horário.
Use a ferramenta SQL Server para exportar a definição de objetos de banco de dados para um arquivo SQL que deve incluir: tabelas, exibições, gatilhos, SPs, funções e assim por diante
Edite o arquivo SQL (faça um backup primeiro) usando qualquer editor de texto que permita encontrar o texto
"GETDATE()"
e substituí-lo por"[dbo].[getlocaldate]()"
Execute o arquivo SQL editado no Azure SQL para criar seus objetos de banco de dados...
Execute a migração de dados.
Aqui você tem uma referência da documentação do Azure: Gerando Scripts para SQL Azure
Eu trabalharia ao contrário. Converta todos os seus carimbos de data/hora no banco de dados para UTC, use apenas UTC e siga o fluxo. Se você precisar de um carimbo de data/hora em um tz diferente, poderá criar uma coluna gerada usando
AT TIME ZONE
(como fez acima) que renderiza o carimbo de data/hora nesse TZ especificado (para o aplicativo). Mas, eu consideraria seriamente apenas ter o UTC retornado ao aplicativo e escrever essa lógica - a lógica de exibição - no aplicativo.Em vez de exportar, editar manualmente e executar novamente, você pode tentar fazer o trabalho diretamente no banco de dados com algo como:
é claro, estendendo-o para lidar com funções, gatilhos e assim por diante também.
Existem algumas ressalvas:
Você pode precisar ser um pouco mais brilhante e lidar com espaços em branco diferentes/extras entre
CREATE
ePROCEDURE
/VIEW
/<other>
. Em vez doREPLACE
para isso, você pode preferir deixar oCREATE
no lugar e executar umDROP
primeiro, mas isso corre o risco de deixarsys.depends
e amigos fora de ordem ondeALTER
não podem, também seALTER
falhar, você pelo menos tem o objeto existente ainda no lugar, onde comDROP
+CREATE
você pode não.Se o seu código tiver algum cheiro "inteligente" como modificar seu próprio esquema com TSQL ad-hoc, você precisará garantir que a pesquisa e a substituição por
CREATE
->ALTER
não interfiram com isso.Você vai querer testar a regressão de todo o(s) aplicativo(s) após a operação, quer use o cursor ou os métodos export+edit+run.
Eu usei esse método para fazer atualizações semelhantes em todo o esquema no passado. É um pouco hack e parece bastante feio, mas às vezes é a maneira mais fácil/rápida.
Padrões e outras restrições também podem ser modificados de forma semelhante, embora eles só possam ser descartados e recriados em vez de alterados. Algo como:
Um pouco mais de diversão com as quais você pode precisar lidar: se você estiver particionando por tempo, essas partes também precisam ser alteradas. Embora o particionamento no tempo mais granular do que no dia seja raro, você pode ter problemas em que
DATETIME
s são interpretados pela função de particionamento como sendo o dia anterior ou seguinte, dependendo do timezine, deixando suas partições desalinhadas com suas consultas usuais.Eu realmente gosto da resposta de David e aprovo isso para uma maneira programática de fazer as coisas.
Mas você pode tentar isso hoje para um teste no Azure via SSMS:
Clique com o botão direito do mouse em seu banco de dados -> Tarefas -> Gerar scripts.
[Back Story] tivemos um DBA júnior que atualizou todos os nossos ambientes de teste para o SQL 2008 R2 enquanto nossos ambientes de produção estavam no SQL 2008. É uma mudança que me faz estremecer até hoje. Para migrar para produção, de teste, tivemos que gerar scripts dentro do SQL, usando gerar scripts, e nas opções avançadas usamos a opção 'Tipo de dados para script: Esquema e dados' para gerar um arquivo de texto massivo. Conseguimos mover com sucesso nossos bancos de dados R2 de teste para nossos servidores SQL 2008 legados -- onde uma restauração de banco de dados para uma versão inferior não teria funcionado. Usamos o sqlcmd para inserir o arquivo grande - pois os arquivos geralmente eram grandes demais para o buffer de texto do SSMS.
O que estou dizendo aqui é que essa opção provavelmente funcionaria para você também. Você só precisará fazer uma etapa adicional e pesquisar e substituir getdate() por [dbo].getlocaldate no arquivo de texto gerado. (Eu colocaria sua função no banco de dados antes da migração).
(Eu nunca quis ser proficiente nesse curativo de restauração de banco de dados, mas por um tempo se tornou uma maneira de fato de fazer as coisas. E funcionou todas as vezes.)
Se você escolher esta rota, certifique-se e selecione o botão Avançado e selecione todas as opções que você precisa (leia cada uma) para mover do banco de dados antigo para o novo banco de dados - como os padrões que você mencionou. Mas faça alguns testes no Azure. Aposto que você descobrirá que esta é uma solução que funciona -- com um mínimo de esforço.
Observe comentado sysobjects Type column condition.Meu script alterará apenas proc e UDF.
Este script irá alterar tudo o
Default Constraint
que contémGetDate()
Eu votei na resposta de Evan Carrolls, pois acho que essa é a melhor solução. Não consegui convencer meus colegas de que eles deveriam mudar muito código C#, então tive que usar o código que David Spillett escreveu. Corrigi alguns problemas com UDFs, SQL dinâmico e esquemas (nem todos os códigos usam "dbo.") assim:
e as restrições padrão como esta:
UDFs
A sugestão de usar uma UDF que retorne a data e hora de hoje parece legal, mas acho que ainda há problemas de desempenho suficientes com UDFs, então optei por usar a solução AT TIME ZONE muito longa e feia.