web-dev-qa-db-fra.com

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

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, prennent 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 (selon le Data Loading Performance Guide ) et un INSERT...SELECT instruction pour déplacer les données initialement en pensant qu'elles seraient enregistrées de façon minimale. Malheureusement, chaque fois que j'essaie, il est entièrement enregistré.

À 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
24
Kenneth Fisher

Pourquoi n'obtenez-vous pas une journalisation minimale?

J'ai trouvé le Data Loading Performance Guide , auquel vous faites référence, comme 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 Partitioning pour éliminer 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.

enter image description here

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 avec TABLOCK un mois à la fois, en utilisant la commutation de partition pour placer les données dans la table partitionnée.
  • Un DELETE pour effacer l'ancienne table sera entièrement enregistré. Vous pouvez peut-être TRUNCATE ou supprimer la table et créer une nouvelle table d'archive.

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

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

Comme vous pouvez le voir dans 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'indicateur TABLOCK. 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 coup de pouce Nice; nous chargeons généralement au moins quatre partitions à la fois sur du matériel de classe serveur.

enter image description here

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 chargements 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 constaté une réduction à 76 seconds (de 156 seconds Sur 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 un peu plus de 12 minutes sur 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.

11
Geoff Patterson

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 son Stairway Series .

1
MattyZDBA

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.

0
John