Améliorez la vitesse de reconstruction d'index sur le serveur SQL

9

J'importe une grande quantité de données dans une base de données vide et avant de commencer, j'ai désactivé tous les index non cluster non uniques pour voir si je pouvais améliorer les performances de l'importation.

Maintenant, je veux réactiver les index, et je me demande si je peux faire quelque chose pour l'optimiser.

Il y a> 100 tables et près de 2 000 index à reconstruire. La base de données a une taille de 200 Go.

La section clé du script que j'exécute est la suivante:

declare c_toggle_index cursor FORWARD_ONLY READ_ONLY for
    select  'alter index ' + QUOTENAME(i.name) + ' on ' + o.name + ' rebuild'
    from    sys.indexes as i
    Inner Join sys.objects o
    On o.object_id = i.object_id
    Where o.is_ms_shipped = 0
    And i.index_id >= 1
    and i.type > 1
    and i.is_disabled = 1

J'ai envisagé de définir ONLINE = OFF pour l'instruction alter index, mais comme les index commencent désactivés, je n'étais pas sûr que ce paramètre aurait un effet. J'ai également envisagé de définir SORT_IN_TEMPDB = ON, mais comme les fichiers tempdb sont sur le même lecteur que les fichiers .mdf des bases de données, j'ai supposé qu'il n'y avait également aucun avantage à le faire.

Lors de l'exécution du script de reconstruction, j'ai remarqué que j'avais beaucoup de types d'attente CXPACKET. Je ne comprends pas vraiment pourquoi ce serait ou si c'est un problème que je devrais chercher à résoudre.

Un dernier point qui peut être pertinent: l'ensemble de mon serveur est actuellement inactif à part cette importation de données dans la base de données. Il n'y a aucune autre activité utilisateur à considérer ou à s'inquiéter; ma seule préoccupation est d'importer les données dans la base de données dans les plus brefs délais.

paulH
la source
3
Lorsque vous dites que votre seule préoccupation est le temps d'importation, voulez-vous dire le temps entre le début de l'importation et la fin de la réactivation des index? Si tel est le cas, vous devez simplement laisser les index activés lors de l'importation. 2 000 index pour 200 Go de données me paraissent beaucoup d'index. Vous devriez peut-être regarder les DMV d'utilisation de l'index pour voir s'il y en a qui pourraient être supprimés.
Max Vernon
1
Juste pour clarifier, vous devez faire la même importation de 200 Go à plusieurs reprises, et pas seulement une fois?
Jon Seigel
1
Je n'ai besoin d'importer qu'une seule fois, mais dans le cadre d'un processus plus vaste avec une fenêtre de temps limitée, donc je teste actuellement ce processus pour l'adapter à cette fenêtre. @MaxVernon Il semble que vous ayez raison de laisser les index activés est le moyen le plus rapide, bien que je sois surpris car j'ai lu qu'il était normalement plus rapide de désactiver les index, d'importer les données, puis de réactiver les index. Il s'agit d'une base de données tierce, donc la suppression d'index ou sa modification n'est pas vraiment possible.
paHe
3
D'accord. À propos des CXPACKETattentes: les reconstructions d'index elles-mêmes analysent les index (même l'index en cours de reconstruction ), et ces analyses peuvent utiliser le parallélisme. Vous ne devriez pas vous inquiéter de ces attentes - le parallélisme est probablement utile.
Jon Seigel

Réponses:

10

Atteindre des performances d'importation optimales dans ce scénario nécessite trois choses:

  1. Inserts de table de base à journalisation minimale
  2. Générations d'index non cluster à journalisation minimale
  3. Éviter les lectures physiques

Journalisation minimale

La réalisation d'insertions à journalisation minimale dans une table en cluster vide sans index non cluster nécessite:

  1. Utilisation du SIMPLEou BULK_LOGGEDdes modèles de récupération de base de données
  2. Spécification d'un verrou de table et d'une entrée ordonnée (par exemple TABLOCKet ORDERastuces)

Note latérale:

Il est également possible d'obtenir des insertions à journalisation minimale dans une table en cluster qui possède des index non clusterisés à condition que l'indicateur de trace 610 soit activé. Le fait que les insertions d'index non cluster soient ou non journalisées de manière minimale dépend du plan de requête sélectionné par l'optimiseur de requête.

Si le plan de requête utilise un itérateur distinct pour l'index non cluster et que l'itérateur a la DMLRequestSortpropriété définie sur true, les insertions d'index non cluster seront enregistrées de manière minimale, à condition que les autres conditions mentionnées précédemment soient remplies.

Création d'index non cluster séparément

Les avantages de cette opération sont les suivants:

  1. Les insertions d'index en cluster peuvent être enregistrées de manière minimale sans activer TF 610
  2. CREATE INDEX est enregistré de façon minimale si le modèle de récupération n'est pas FULL

Éviter les lectures physiques

Idéalement, les données à importer seront stockées sur une machine distincte, ou au moins sur un stockage physique distinct de celui utilisé pour héberger la base de données.

Le serveur de base de données doit avoir suffisamment de mémoire pour contenir la plus grande table de base dans le cache, avec suffisamment de mémoire pour les opérations de tri nécessaires lors de la création d'index non cluster.

Un bon modèle consiste à charger rapidement la table de base (charge d'index clusterisée à journalisation minimale), puis à créer tous les index non cluster pour cette table pendant que ses pages de données sont toujours mises en cache.

La question décrit un processus par lequel les tables de base sont chargées en premier, puis les index non cluster sont construits. La définition du curseur n'utilise pas de ORDER BYclause pour regrouper au moins les générations d'index non cluster sur la même table.

Le résultat probable est que les pages de données de différentes tables sont lues à plusieurs reprises dans le cache, puis supprimées car les index non clusterisés sont créés dans un ordre non déterministe.

Le coût des lectures physiques répétées domine complètement les avantages d'une journalisation minimale obtenue en créant des index non-cluster séparément. Cela explique pourquoi vous avez constaté que le chargement des tables avec des index existants est plus rapide (car tous les index non cluster pour une table donnée sont conservés avant de passer à la table suivante).

Sommaire

Le processus d'importation doit être retravaillé pour charger en bloc une table à la fois. Cela signifie charger la table et construire tous les index non cluster avant de passer au suivant. L'instance SQL Server doit avoir suffisamment de mémoire disponible pour contenir la plus grande table et effectuer le plus grand tri d'index non cluster en même temps.

Vous pouvez également essayer d'activer TF 610 avant de charger les données dans des tables avec des index non cluster déjà en place. Ce n'est généralement pas aussi rapide que la méthode précédente, mais cela peut être assez rapide.

Consultez les informations suivantes pour plus d'informations:

Le guide des performances de chargement des données

Opérations pouvant être enregistrées de façon minimale

Paul White 9
la source