J'ai donc un processus d'insertion en bloc simple pour prendre les données de notre table de transfert et les déplacer dans notre datamart.
Le processus est une tâche de flux de données simple avec des paramètres par défaut pour "Lignes par lot" et les options sont "tablock" et "no check constraint".
La table est assez grande. 587 162 986 avec une taille de données de 201 Go et 49 Go d'espace d'index. L'index cluster de la table est.
CREATE CLUSTERED INDEX ImageData ON dbo.ImageData
(
DOC_ID ASC,
ACCT_NUM ASC,
MasterID ASC
)
Et la clé primaire est:
ALTER TABLE dbo.ImageData
ADD CONSTRAINT ImageData
PRIMARY KEY NONCLUSTERED
(
ImageID ASC,
DT_CRTE_DOC ASC
)
Maintenant, nous avons eu un problème où BULK INSERT
via SSIS fonctionne incroyablement lentement. 1 heure pour insérer un million de lignes. La requête qui remplit la table est déjà triée et la requête à remplir prend moins d'une minute pour s'exécuter.
Lorsque le processus est en cours d'exécution, je peux voir la requête en attente sur l'insertion BULK qui prend entre 5 et 20 secondes et affiche un type d'attente de PAGEIOLATCH_EX
. Le processus ne peut traiter qu'un INSERT
millier de lignes à la fois.
Hier, lors du test de ce processus par rapport à mon environnement UAT, je rencontrais le même problème. J'exécutais le processus plusieurs fois et essayais de déterminer la cause première de cette insertion lente. Puis tout d'un coup, il a commencé à fonctionner en moins de 5 minutes. Je l'ai donc couru quelques fois de plus avec le même résultat. De plus, le nombre d'inserts en vrac qui attendaient pendant 5 secondes ou plus a chuté de centaines à environ 4.
Maintenant, cela laisse perplexe parce que ce n'est pas comme si nous avions eu une énorme baisse d'activité.
Le processeur pendant la durée est faible.
Les moments où il est plus lent semblent avoir moins d'attentes sur le disque.
La latence du disque augmente en fait pendant la période d'exécution du processus en moins de 5 minutes.
Et l'IO était beaucoup plus faible pendant les périodes où ce processus fonctionnait mal.
J'ai déjà vérifié et il n'y a pas eu de croissance de fichiers car les fichiers ne sont pleins qu'à 70%. Il reste encore 50% au fichier journal. La base de données est en mode de récupération simple. DB n'a qu'un seul groupe de fichiers mais est réparti sur 4 fichiers.
Donc, je me demande A: pourquoi voyais-je des temps d'attente aussi longs sur ces encarts en vrac. B: quelle sorte de magie s'est produite qui l'a rendu plus rapide?
Note de côté. Il fonctionne à nouveau comme de la merde aujourd'hui.
MISE À JOUR, il est actuellement partitionné. Cependant, cela se fait dans une méthode qui est au mieux idiote.
CREATE PARTITION SCHEME [ps_Image] AS PARTITION [pf_Image]
TO ([FG_Image], [FG_Image], [FG_Image], [FG_Image])
CREATE PARTITION FUNCTION [pf_Image](datetime) AS
RANGE RIGHT FOR VALUES (
N'2011-12-01T00:00:00.000'
, N'2013-04-01T00:00:00.000'
, N'2013-07-01T00:00:00.000'
);
Cela laisse essentiellement toutes les données dans la 4ème partition. Cependant, comme tout va dans le même groupe de fichiers. Les données sont actuellement réparties assez uniformément entre ces fichiers.
MISE À JOUR 2 Ce sont les attentes globales lorsque le processus ne fonctionne pas correctement.
Ce sont les attentes pendant la période pendant laquelle j'ai pu exécuter le processus qui fonctionne bien.
Le sous-système de stockage est un RAID connecté localement, aucun SAN n'est impliqué. Les journaux se trouvent sur un autre lecteur. Le contrôleur RAID est le PERC H800 avec une taille de cache de 1 Go. (Pour UAT) Prod est un PERC (810).
Nous utilisons une récupération simple sans sauvegarde. Il est restauré à partir d'une copie de production tous les soirs.
Nous avons également mis IsSorted property = TRUE
en SSIS puisque les données sont déjà triées.
ASYNC_NETWORK_IO
signifie que SQL Server attendait d' envoyer des lignes à un client quelque part. Je suppose que cela montre l'activité de SSIS consommant des lignes de la table de transfert.PAGEIOLATCH_EX
etASYNC_IO_COMPLETION
indiquent qu'il faut un certain temps pour obtenir des données du disque dans la mémoire. Cela peut être un indicateur d'un problème avec le sous-système de disque, ou il peut s'agir d'un conflit de mémoire. De combien de mémoire dispose SQL Server?Réponses:
Je ne peux pas indiquer la cause, mais je crois que les lignes par lot par défaut pour une opération BULK INSERT sont "toutes". La définition d'une limite dans les lignes pourrait rendre l'opération plus digeste: c'est pourquoi c'est une option. (Ici et là, je regarde la documentation Transact-SQL "BULK INSERT", donc ça pourrait être loin pour SSIS.)
Cela aura pour effet de diviser l'opération en plusieurs lots de X lignes, chacune fonctionnant comme une transaction distincte. S'il y a une erreur, les lots terminés resteront validés dans la table de destination et le lot qui a été arrêté sera annulé. Si cela est tolérable dans ce que vous faites, c'est-à-dire que vous pouvez le réexécuter plus tard et rattraper votre retard, essayez cela.
Ce n'est pas faux d'avoir une fonction de partition qui place toutes les insertions actuelles dans une seule partition de table, mais je ne vois pas comment il est utile de partitionner du tout avec des partitions dans le même groupe de fichiers. Et l'utilisation de datetime est médiocre, et en fait un peu cassée pour datetime et 'YYYY-MM-DD' sans formule CONVERT explicite depuis SQL Server 2008 (SQL peut traiter gaiement cela comme YYYY-DD-MM: sans blague: pas de panique, il suffit de le changer en 'YYYYMMDD', fixe: ou CONVERT (datetime, 'YYYY-MM-DDT00: 00: 00', 126), je pense que c'est le cas). Mais je pense que l'utilisation d'un proxy pour la valeur de la date (année en tant qu'int ou année + trimestre) pour partitionner fonctionnera mieux.
Peut-être que c'est une conception copiée d'ailleurs, ou dupliquée sur plusieurs datamarts. Si cela est un vrai datamart, un vidage de l'entrepôt de données pour donner aux chefs de service des données avec lesquelles jouer, qui ne sont pas (par vous) envoyés ailleurs, et probablement en lecture seule en ce qui concerne les utilisateurs de données , alors, il me semble que vous pouvez supprimer la fonction de partition - ou - la changer pour mettre explicitement toutes les nouvelles données dans la quatrième partition, quoi qu'il en soit, et personne ne s'en soucierait. (Vous devriez peut-être vérifier que personne ne s'en soucie.)
Cela ressemble à une conception où le plan est de supprimer le contenu de la partition 1 dans le futur et de créer une nouvelle partition pour plus de nouvelles données, mais cela ne semble pas se produire ici. Au moins, cela ne s'est pas produit depuis 2013.
la source
J'ai vu cette même lenteur extrême sporadique sur les insertions de grandes tables partitionnées à l'occasion moi-même. Avez-vous essayé de mettre à jour les statistiques des tables de destination, puis de recommencer? Le temps d'attente extrême pourrait être dû à de mauvaises statistiques, et si une mise à jour des statistiques était déclenchée à un moment donné pendant vos tests, cela expliquerait l'augmentation de la vitesse. Juste une pensée et un test facile à vérifier.
la source