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...SELECT
instruction 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
la source
Réponses:
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 Partitioning
pour 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.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:
Les différences par rapport à votre approche d'origine:
TABLOCK
un mois à la fois, en utilisant la commutation de partition pour placer les données dans la table partitionnée.DELETE
pour effacer l'ancienne table sera entièrement enregistré. Vous pouvez peut-êtreTRUNCATE
soit 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 row
ensemble 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'
TABLOCK
indice. 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.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
(depuis156 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 le relais12 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.la source
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 .
la source
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.
la source