Quelle est la meilleure façon d'archiver tout sauf l'année en cours et de partitionner la table en même temps


23

Tâche

Archivez tout sauf une période continue de 13 mois à partir d'un groupe de grandes tables. Les données archivées doivent être stockées dans une autre base de données.

  • La base de données est en mode de récupération simple
  • Les tableaux sont des rangées de 50 mil à plusieurs milliards et, dans certains cas, occupent des centaines de Go chacun.
  • Les tables ne sont actuellement pas partitionnées
  • Chaque table possède un index cluster sur une colonne de date toujours croissante
  • Chaque table possède en outre un index non clusterisé
  • Toutes les modifications de données apportées aux tableaux sont des insertions
  • L'objectif est de minimiser les temps d'arrêt de la base de données primaire.
  • Le serveur est 2008 R2 Enterprise

La table "archive" aura environ 1,1 milliard de lignes, la table "live" environ 400 millions. Évidemment, la table d'archives augmentera avec le temps, mais je m'attends à ce que la table en direct augmente également assez rapidement. Disons 50% au moins au cours des deux prochaines années.

J'avais pensé aux bases de données extensibles Azure, mais malheureusement, nous sommes à 2008 R2 et nous y resterons probablement un certain temps.

Plan actuel

  • Créer une nouvelle base de données
  • Créez de nouvelles tables partitionnées par mois (en utilisant la date modifiée) dans la nouvelle base de données.
  • Déplacez les 12-13 derniers mois de données dans les tables partitionnées.
  • Effectuer un changement de nom des deux bases de données
  • Supprimez les données déplacées de la base de données désormais "archive".
  • Partitionnez chacune des tables de la base de données "archive".
  • Utilisez les échanges de partitions pour archiver les données à l'avenir.
    • Je me rends compte que je vais devoir échanger les données à archiver, copier cette table dans la base de données d'archive, puis l'échanger dans la table d'archive. C'est acceptable.

Problème: j'essaie de déplacer les données dans les tables partitionnées initiales (en fait, je fais encore une preuve de concept dessus). J'essaie d'utiliser TF 610 (conformément au Guide de performance de chargement des données ) et une INSERT...SELECTinstruction pour déplacer les données en pensant initialement qu'elles seraient enregistrées de manière minimale. Malheureusement, chaque fois que j'essaie, il est entièrement connecté.

À ce stade, je pense que mon meilleur pari pourrait être de déplacer les données à l'aide d'un package SSIS. J'essaie d'éviter cela car je travaille avec 200 tables et tout ce que je peux faire par script, je peux facilement le générer et l'exécuter.

Y a-t-il quelque chose qui me manque dans mon plan général, et SSIS est-il mon meilleur pari pour déplacer les données rapidement et avec une utilisation minimale du journal (problèmes d'espace)?

Code de démonstration sans données

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

Déplacer le code

USE Audit_New
GO
DBCC TRACEON(610);

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

RE "déplacer les données": pour minimiser l'utilisation des journaux, vous pouvez déplacer des données par lots, par exemple "Approch 2" dans dba.stackexchange.com/a/139009/94130 . En ce qui concerne le partitionnement, avez-vous envisagé des vues partitionnées?
Alex

@Alex Oui, j'ai considéré les deux. Mon plan de sauvegarde consiste à déplacer les données par lots à l'aide de SSIS. Et pour ce cas particulier, mon problème est exactement à quoi sert le partitionnement. (chargement / déchargement rapide des données à l'aide de la commutation)
Kenneth Fisher

Réponses:


10

Pourquoi n'obtenez-vous pas une journalisation minimale?

J'ai trouvé que le Data Loading Performance Guide , auquel vous faites référence, est une ressource extrêmement précieuse. Cependant, il n'est pas non plus complet à 100%, et je soupçonne que la grille est déjà suffisamment complexe pour que l'auteur n'ait pas ajouté de colonne Table Partitioningpour expliquer les différences de comportement selon que la table recevant les insertions est partitionnée. Comme nous le verrons plus loin, le fait que la table est déjà partitionnée semble inhiber la journalisation minimale.

entrez la description de l'image ici

Approche recommandée

Sur la base des recommandations du Guide de performances de chargement de données (y compris la section "Chargement en bloc d'une table partitionnée") ainsi que d'une vaste expérience du chargement de tables partitionnées avec des dizaines de milliards de lignes, voici l'approche que je recommanderais:

  • Créez une nouvelle base de données.
  • Créez de nouvelles tables partitionnées par mois dans la nouvelle base de données.
  • Déplacer l'année de données la plus récente, de la manière suivante:
    • Pour chaque mois, créez une nouvelle table de tas;
    • Insérez ce mois de données dans le tas à l'aide de l'indice TABLOCK;
    • Ajoutez l'index cluster au tas contenant ce mois de données;
    • Ajoutez la contrainte de vérification en faisant en sorte que la table ne contienne que les données de ce mois;
    • Basculez la table dans la partition correspondante de la nouvelle table partitionnée globale.
  • Effectuez un changement de nom des deux bases de données.
  • Tronquez les données dans la base de données désormais "archive".
  • Partitionnez chacune des tables de la base de données "archive".
  • Utilisez les échanges de partitions pour archiver les données à l'avenir.

Les différences par rapport à votre approche d'origine:

  • La méthodologie de déplacement des 12-13 derniers mois de données sera beaucoup plus efficace si vous chargez dans un segment de mémoire avec TABLOCKun mois à la fois, en utilisant la commutation de partition pour placer les données dans la table partitionnée.
  • Un DELETEpour effacer l'ancienne table sera entièrement enregistré. Vous pouvez peut-être TRUNCATEsoit supprimer la table et créer une nouvelle table d'archives.

Comparaison des approches pour déplacer la dernière année de données

Afin de comparer les approches dans un temps raisonnable sur ma machine, j'ai utilisé un 100MM rowensemble de données de test que j'ai généré et qui suit votre schéma.

Comme vous pouvez le voir sur les résultats ci-dessous, il y a une augmentation importante des performances et une réduction des écritures de journal en chargeant les données dans un tas à l'aide de l' TABLOCKindice. Il y a un avantage supplémentaire si cela se fait une partition à la fois. Il convient également de noter que la méthode une partition à la fois peut facilement être parallélisée davantage si vous exécutez plusieurs partitions à la fois. Selon votre matériel, cela pourrait donner un bon coup de pouce; nous chargeons généralement au moins quatre partitions à la fois sur du matériel de classe serveur.

entrez la description de l'image ici

Voici le script de test complet .

Notes finales

Tous ces résultats dépendent dans une certaine mesure de votre matériel. Cependant, mes tests ont été effectués sur un ordinateur portable quad-core standard avec lecteur de disque rotatif. Il est probable que les charges de données devraient être beaucoup plus rapides si vous utilisez un serveur décent qui n'a pas beaucoup d'autres charges au moment où vous effectuez ce processus.

Par exemple, j'ai exécuté l'approche recommandée sur un serveur de développement réel (Dell R720) et j'ai vu une réduction à 76 seconds(depuis 156 secondssur mon ordinateur portable). Fait intéressant, l'approche originale d'insertion dans une table partitionnée n'a pas connu la même amélioration et a tout de même pris le relais 12 minutessur le serveur de développement. Vraisemblablement, c'est parce que ce modèle produit un plan d'exécution en série, et un seul processeur sur mon ordinateur portable peut correspondre à un seul processeur sur le serveur de développement.


Merci encore Geoff. J'utilise la méthode SWITCH. Plus précisément, j'utilise SSIS et SQL dynamique pour exécuter les 13 mois en parallèle.
Kenneth Fisher

1

Cela peut être un bon candidat pour Biml. Une approche consisterait à créer un modèle réutilisable qui migrerait les données d'une seule table dans de petites plages de dates avec un conteneur For Each. Le Biml parcourrait votre collection de tables pour créer des packages identiques pour chaque table éligible. Andy Leonard a une intro dans sa série Stairway .


0

Peut-être qu'au lieu de créer la nouvelle base de données, restaurez la vraie base de données dans une nouvelle base de données et supprimez les données les plus récentes de 12 à 13 mois. Ensuite, dans votre vraie base de données, supprimez les données qui ne sont pas contenues dans la zone d'archivage que vous venez de créer. Si les suppressions importantes sont un problème, vous pouvez peut-être simplement supprimer des ensembles de 10 Ko ou plus par le biais d'un script pour le faire.

Vos tâches de partitionnement ne semblent pas interférer et semblent applicables à l'une ou l'autre base de données après vos suppressions.


Je l'ai déjà fait avec des bases de données plus petites. Compte tenu de la taille actuelle et du fait que je souhaite me retrouver avec des tables partitionnées des deux côtés, je pense que cette méthode prendrait en fait plus de temps et un peu plus d'espace (double la taille actuelle de la base de données au minimum)
Kenneth Fisher
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.