Qual é a melhor maneira de arquivar tudo menos o ano atual e particionar a tabela ao mesmo tempo


23

Tarefa

Arquive todos, exceto um período de 13 meses consecutivos, de um grupo de tabelas grandes. Os dados arquivados devem ser armazenados em outro banco de dados.

  • O banco de dados está no modo de recuperação simples
  • As tabelas são de 50 mil linhas a vários bilhões e, em alguns casos, ocupam centenas de GB cada.
  • As tabelas atualmente não estão particionadas
  • Cada tabela possui um índice em cluster em uma coluna de data sempre crescente
  • Cada tabela possui adicionalmente um índice não agrupado em cluster
  • Todas as alterações de dados nas tabelas são inserções
  • O objetivo é minimizar o tempo de inatividade do banco de dados primário.
  • O servidor é 2008 R2 Enterprise

A tabela "archive" terá cerca de 1,1 bilhão de linhas, a tabela "live", cerca de 400 milhões. Obviamente, a tabela de arquivamento aumentará com o tempo, mas espero que a tabela ao vivo aumente razoavelmente rapidamente também. Diga 50% nos próximos dois anos, pelo menos.

Eu tinha pensado nos bancos de dados de expansão do Azure, mas infelizmente estamos no 2008 R2 e provavelmente permaneceremos lá por um tempo.

Plano atual

  • Crie um novo banco de dados
  • Crie novas tabelas particionadas por mês (usando a data modificada) no novo banco de dados.
  • Mova os últimos 12 a 13 meses de dados para as tabelas particionadas.
  • Faça uma troca de renomeação dos dois bancos de dados
  • Exclua os dados movidos do banco de dados "arquivar" agora.
  • Particione cada uma das tabelas no banco de dados "arquivar".
  • Use trocas de partição para arquivar os dados no futuro.
    • Percebo que terei que trocar os dados a serem arquivados, copiar essa tabela no banco de dados de arquivamento e depois trocá-lo na tabela de arquivamento. Isso é aceitável.

Problema: estou tentando mover os dados para as tabelas particionadas iniciais (na verdade, ainda estou fazendo uma prova de conceito). Estou tentando usar o TF 610 (conforme o Guia de desempenho de carregamento de dados ) e umINSERT...SELECT instrução para mover os dados inicialmente pensando que seriam minimamente registrados. Infelizmente, toda vez que eu tento está totalmente logado.

Neste ponto, estou pensando que minha melhor aposta pode ser mover os dados usando um pacote SSIS. Estou tentando evitar isso, já que estou trabalhando com 200 tabelas e qualquer coisa que eu possa fazer por script, posso gerar e executar facilmente.

Há algo que esteja faltando em meu plano geral e o SSIS é minha melhor aposta para mover os dados rapidamente e com o uso mínimo do log (preocupações com espaço)?

Código de demonstração sem dados

-- Existing structure
USE [Audit]
GO

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
); 
-- ~1.4 bill rows, ~20% in the last year

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(   [Modified] ASC   )
GO


-- New DB & Code
USE Audit_New
GO

CREATE PARTITION FUNCTION ThirteenMonthPartFunction (datetime)
AS RANGE RIGHT FOR VALUES ('20150701', '20150801', '20150901', '20151001', '20151101', '20151201', 
                            '20160101', '20160201', '20160301', '20160401', '20160501', '20160601', 
                            '20160701') 

CREATE PARTITION SCHEME ThirteenMonthPartScheme AS PARTITION ThirteenMonthPartFunction
ALL TO ( [PRIMARY] );

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
) ON ThirteenMonthPartScheme (Modified)
GO

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

CREATE NONCLUSTERED INDEX [AuditTable_Col1_Col2_Col3_Col4_Modified] ON [dbo].[AuditTable]
(
    [Col1] ASC,
    [Col2] ASC,
    [Col3] ASC,
    [Col4] ASC,
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

Mover código

USE Audit_New
GO
DBCC TRACEON(610);

INSERT INTO AuditTable
SELECT * FROM Audit.dbo.AuditTable
WHERE Modified >= '6/1/2015'
ORDER BY Modified

RE "mover os dados": para minimizar o uso do log, você pode mover os dados em lotes, por exemplo, "Aproximação 2" em dba.stackexchange.com/a/139009/94130 . Sobre o assunto do particionamento, você considerou visualizações particionadas?
21716 Alex

@ Alex Sim, eu considerei os dois. Meu plano de backup é mover os dados em lotes usando o SSIS. E, nesse caso em particular, meu problema é exatamente para o qual o particionamento foi criado. (carga rápida / descarregamento de dados usando comutação)
Kenneth Fisher

Respostas:


10

Por que você não está obtendo log mínimo?

Eu achei o Guia de Desempenho de Carregamento de Dados , que você mencionou, um recurso extremamente valioso. No entanto, também não é 100% abrangente, e suspeito que a grade já seja suficientemente complexa para que o autor não tenha adicionado uma coluna Table Partitioningpara quebrar as diferenças de comportamento, dependendo se a tabela que recebe as inserções está particionada. Como veremos mais adiante, o fato de a tabela já estar particionada parece inibir o registro mínimo.

insira a descrição da imagem aqui

Abordagem recomendada

Com base nas recomendações do Guia de desempenho de carregamento de dados (incluindo a seção "Carregamento em massa de uma tabela particionada"), bem como uma vasta experiência no carregamento de tabelas particionadas com dezenas de bilhões de linhas, eis a abordagem que eu recomendaria:

  • Crie um novo banco de dados.
  • Crie novas tabelas particionadas por mês no novo banco de dados.
  • Mova o ano mais recente dos dados, da seguinte maneira:
    • Para cada mês, crie uma nova tabela de heap;
    • Insira esse mês de dados no heap usando a dica TABLOCK;
    • Adicione o índice de cluster ao heap que contém esse mês de dados;
    • Adicione a restrição de verificação impondo que a tabela contenha apenas os dados deste mês;
    • Alterne a tabela para a partição correspondente da nova tabela particionada geral.
  • Faça uma troca de renomeação dos dois bancos de dados.
  • Trunque os dados no agora banco de dados "arquivar".
  • Particione cada uma das tabelas no banco de dados "arquivar".
  • Use trocas de partição para arquivar os dados no futuro.

As diferenças quando comparadas à sua abordagem original:

  • A metodologia de mover os últimos 12 a 13 meses de dados será muito mais eficiente se você carregar um heap com TABLOCKum mês de cada vez, usando a alternância de partições para colocar os dados na tabela particionada.
  • A DELETEpara limpar a tabela antiga será totalmente registrada. Talvez você possa TRUNCATEou solte a tabela e crie uma nova tabela de arquivamento.

Comparação de abordagens para mover o ano recente de dados

Para comparar abordagens em uma quantidade razoável de tempo na minha máquina, usei um 100MM rowconjunto de dados de teste que eu gerava e que segue o seu esquema.

Como você pode ver nos resultados abaixo, há um grande aumento no desempenho e redução nas gravações de log, carregando dados em um heap usando a TABLOCKdica. Há um benefício adicional se isso for feito uma partição por vez. Também vale a pena notar que o método de uma partição por vez pode ser facilmente paralelizado ainda mais se você executar várias partições ao mesmo tempo. Dependendo do seu hardware, isso pode gerar um bom impulso; normalmente carregamos pelo menos quatro partições ao mesmo tempo no hardware da classe de servidor.

insira a descrição da imagem aqui

Aqui está o script de teste completo .

Notas finais

Todos esses resultados dependem do seu hardware até certo ponto. No entanto, meus testes foram conduzidos em um laptop quad-core padrão com unidade de disco giratório. É provável que as cargas de dados sejam muito mais rápidas se você estiver usando um servidor decente que não tenha muita outra carga no momento em que estiver conduzindo esse processo.

Por exemplo, executei a abordagem recomendada em um servidor de desenvolvimento real (Dell R720) e vi uma redução de 76 seconds(de 156 secondsno meu laptop). Curiosamente, a abordagem original de inserção em uma tabela particionada não teve a mesma melhoria e ainda assumiu o controle 12 minutesno servidor de desenvolvimento. Presumivelmente, isso ocorre porque esse padrão gera um plano de execução serial e um único processador no meu laptop pode corresponder a um único processador no servidor de desenvolvimento.


Mais uma vez obrigado Geoff. Estou usando o método SWITCH. Especificamente, estou usando SSIS e SQL dinâmico para executar os 13 meses em paralelo.
Kenneth Fisher

1

Este pode ser um bom candidato para Biml. Uma abordagem seria criar um modelo reutilizável que migrasse dados para uma única tabela em pequenos períodos com um contêiner For Each. O Biml percorreria sua coleção de tabelas para criar pacotes idênticos para cada tabela qualificada. Andy Leonard tem uma introdução em sua Stairway Series .


0

Talvez, em vez de criar o novo banco de dados, restaure o banco de dados real para um novo banco de dados e exclua os dados mais recentes de 12 a 13 meses. Em seu banco de dados real, exclua os dados que não estão contidos na área de arquivamento recém-criada. Se exclusões grandes forem um problema, talvez você possa excluir conjuntos de 10 K ou mais por meio de script para fazer isso.

Suas tarefas de particionamento não parecem interferir e parecem ser aplicáveis ​​a qualquer banco de dados após suas exclusões.


Eu fiz isso com bancos de dados menores antes. Dado o tamanho atual eo fato de que eu quero acabar com tabelas particionadas em ambos os lados eu acho que este método seria realmente levar mais tempo e um pouco mais de espaço (o dobro do tamanho DB atual em min)
Kenneth Fisher
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.