Qual è il modo migliore per archiviare tutti tranne l'anno in corso e partizionare la tabella allo stesso tempo


23

Compito

Archivia tutti tranne un periodo di 13 mesi a rotazione da un gruppo di grandi tabelle. I dati archiviati devono essere archiviati in un altro database.

  • Il database è in modalità di recupero semplice
  • Le tabelle sono da 50 mil file a diversi miliardi e in alcuni casi occupano centinaia di GB ciascuno.
  • Le tabelle non sono attualmente partizionate
  • Ogni tabella ha un indice cluster su una colonna di data sempre crescente
  • Ogni tabella ha inoltre un indice non cluster
  • Tutte le modifiche ai dati delle tabelle sono inserti
  • L'obiettivo è ridurre al minimo i tempi di inattività del database primario.
  • Il server è 2008 R2 Enterprise

La tabella "archivio" avrà circa 1,1 miliardi di righe, la tabella "live" circa 400 milioni. Ovviamente la tabella degli archivi aumenterà nel tempo, ma mi aspetto che anche la tabella live aumenti abbastanza rapidamente. Di 'almeno il 50% nei prossimi due anni.

Avevo pensato ai database stretch di Azure, ma sfortunatamente siamo al 2008 R2 e probabilmente resteremo lì per un po '.

Piano attuale

  • Crea un nuovo database
  • Crea nuove tabelle partizionate per mese (usando la data modificata) nel nuovo database.
  • Sposta gli ultimi 12-13 mesi di dati nelle tabelle partizionate.
  • Eseguire uno scambio di ridenominazione dei due database
  • Elimina i dati spostati dal database ora "archivio".
  • Partizionare ciascuna delle tabelle nel database "archivio".
  • Utilizzare gli scambi di partizioni per archiviare i dati in futuro.
    • Mi rendo conto che dovrò scambiare i dati da archiviare, copiare quella tabella nel database di archivio e quindi scambiarli nella tabella di archivio. Questo è accettabile

Problema: sto cercando di spostare i dati nelle tabelle partizionate iniziali (in effetti sto ancora facendo una prova del concetto su di esso). Sto cercando di utilizzare TF 610 (secondo la Guida alle prestazioni di caricamento dei dati ) e INSERT...SELECTun'istruzione per spostare i dati inizialmente pensando che sarebbero stati minimamente registrati. Purtroppo ogni volta che provo è completamente registrato.

A questo punto sto pensando che la mia scommessa migliore potrebbe essere quella di spostare i dati usando un pacchetto SSIS. Sto cercando di evitare che dal momento che sto lavorando con 200 tabelle e tutto ciò che posso fare con lo script posso facilmente generare ed eseguire.

C'è qualcosa che mi manca nel mio piano generale e SSIS è la mia migliore scommessa per spostare i dati rapidamente e con un uso minimo del registro (problemi di spazio)?

Codice demo senza dati

-- 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

Sposta codice

USE Audit_New
GO
DBCC TRACEON(610);

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

RE "sposta i dati": per ridurre al minimo l'utilizzo del registro è possibile spostare i dati in batch, ad esempio "Approch 2" in dba.stackexchange.com/a/139009/94130 . A proposito del partizionamento hai preso in considerazione le viste partizionate?
Alex,

@Alex Sì, ho considerato entrambi. Il mio piano di backup è spostare i dati in batch utilizzando SSIS. E per questo caso particolare il mio problema è esattamente quello per cui è stato creato il partizionamento. (caricamento / scaricamento rapido dei dati mediante commutazione)
Kenneth Fisher,

Risposte:


10

Perché non si ottiene una registrazione minima?

Ho trovato la Guida alle prestazioni di caricamento dei dati , a cui fai riferimento, per essere una risorsa estremamente preziosa. Tuttavia, non è nemmeno completo al 100% e sospetto che la griglia sia già abbastanza complessa che l'autore non ha aggiunto una colonna Table Partitioningper distinguere le differenze di comportamento a seconda che la tabella che riceve gli inserti sia partizionata. Come vedremo più avanti, il fatto che la tabella sia già partizionata sembra inibire la registrazione minima.

inserisci qui la descrizione dell'immagine

Approccio raccomandato

Sulla base delle raccomandazioni contenute nella Guida alle prestazioni del caricamento dei dati (inclusa la sezione "Caricamento in blocco di una tabella partizionata") e della vasta esperienza nel caricamento di tabelle partizionate con decine di miliardi di righe, ecco l'approccio che consiglierei:

  • Crea un nuovo database.
  • Crea nuove tabelle partizionate per mese nel nuovo database.
  • Spostare l'anno più recente di dati, nel modo seguente:
    • Per ogni mese, creare una nuova tabella heap;
    • Inserisci quel mese di dati nell'heap usando il suggerimento TABLOCK;
    • Aggiungi l'indice cluster all'heap contenente quel mese di dati;
    • Aggiungi il vincolo di controllo imponendo che la tabella contenga solo i dati di questo mese;
    • Passare la tabella nella partizione corrispondente della nuova tabella partizionata complessiva.
  • Eseguire uno scambio di ridenominazione dei due database.
  • Tronca i dati nel database ora "archivio".
  • Partizionare ciascuna delle tabelle nel database "archivio".
  • Utilizzare gli scambi di partizioni per archiviare i dati in futuro.

Le differenze rispetto all'approccio originale:

  • La metodologia di spostamento degli ultimi 12-13 mesi di dati sarà molto più efficiente se si carica in un heap con TABLOCKun mese alla volta, utilizzando il cambio di partizione per posizionare i dati nella tabella partizionata.
  • A DELETEper cancellare il vecchio tavolo verrà completamente registrato. Forse puoi TRUNCATEo eliminare la tabella e creare una nuova tabella di archivio.

Confronto di approcci per lo spostamento degli ultimi anni di dati

Per confrontare gli approcci in un ragionevole lasso di tempo sulla mia macchina, ho usato un 100MM rowset di dati di test che ho generato e che segue il tuo schema.

Come puoi vedere dai risultati seguenti, c'è un grande aumento delle prestazioni e una riduzione delle scritture dei log caricando i dati in un heap usando il TABLOCKsuggerimento. Vi è un ulteriore vantaggio se ciò viene fatto una partizione alla volta. Vale anche la pena notare che il metodo one-partition-at-a-time può essere facilmente ulteriormente parallelizzato se si eseguono più partizioni contemporaneamente. A seconda del tuo hardware, ciò potrebbe dare una bella spinta; in genere cariciamo almeno quattro partizioni contemporaneamente su hardware di classe server.

inserisci qui la descrizione dell'immagine

Ecco lo script di test completo .

Note finali

Tutti questi risultati dipendono dal tuo hardware in una certa misura. Tuttavia, i miei test sono stati condotti su un laptop quad-core standard con unità disco rotante. È probabile che i carichi di dati dovrebbero essere molto più veloci se si utilizza un server decente che non ha molti altri carichi mentre si sta eseguendo questo processo.

Ad esempio, ho eseguito l'approccio consigliato su un vero server di sviluppo (Dell R720) e ho visto una riduzione a 76 seconds(dal 156 secondsmio laptop). È interessante notare che l'approccio originale dell'inserimento in una tabella partizionata non ha subito lo stesso miglioramento e ha assunto ancora il controllo 12 minutessul server di sviluppo. Presumibilmente questo è perché questo modello produce un piano di esecuzione seriale e un singolo processore sul mio laptop può abbinare un singolo processore sul server dev.


Grazie ancora Geoff. Sto usando il metodo SWITCH. In particolare sto usando SSIS e SQL dinamico per eseguire i 13 mesi in parallelo.
Kenneth Fisher,

1

Questo potrebbe essere un buon candidato per Biml. Un approccio sarebbe quello di creare un modello riutilizzabile che migrasse i dati per una singola tabella in intervalli di date piccoli con un contenitore For Each. Il Biml passerebbe in rassegna la tua raccolta di tabelle per creare pacchetti identici per ogni tabella qualificante. Andy Leonard ha un'introduzione nella sua serie Stairway .


0

Forse, invece di creare il nuovo database, ripristinare il database reale in un nuovo database ed eliminare i dati più recenti, 12-13 mesi. Quindi, nel tuo vero database, elimina i dati che non sono contenuti nell'area di archivio appena creata. Se le eliminazioni di grandi dimensioni sono un problema, forse puoi semplicemente eliminare 10K o set più grandi tramite script per farlo.

Le attività di partizionamento non sembrano interferire e sembrano essere applicabili a nessuno dei database dopo l'eliminazione.


L'ho già fatto con database più piccoli. Date le dimensioni attuali e il fatto che voglio finire con tabelle partizionate su entrambi i lati, penso che questo metodo richiederebbe effettivamente più tempo e un po 'più di spazio (il doppio dell'attuale dimensione del DB al minimo)
Kenneth Fisher,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.