Je fais un projet où je dois changer environ 36K enregistrements dans une table quotidiennement. Je me demande ce qui fonctionnera mieux:
Pour moi, il est plus facile de simplement supprimer toutes les lignes et d'en insérer de nouvelles, mais si cela va fragmenter la table et les index et affecter les performances, je préférerais faire des mises à jour si possible et supprimer/insérer uniquement lorsque cela est nécessaire.
Ce sera un service de nuit et je ne cherche pas à améliorer la vitesse du processus lui-même. Je suis plus préoccupé par les performances des requêtes sur cette table en général où j'ai déjà 89 millions d'enregistrements et comment ce processus nocturne va l'affecter.
Dois-je supprimer/insérer des enregistrements ou dois-je mettre à jour les enregistrements existants (si possible) pour ce processus nocturne?
Cela dépend vraiment de la quantité de données qui change. Disons que ce tableau comporte 20 colonnes. Et vous avez également 5 index - chacun sur un diff. colonne.
Maintenant, si les valeurs dans les 20 colonnes changent OR même si les données dans 5 colonnes changent et que ces 5 colonnes sont toutes indexées, alors il vaut mieux "supprimer et insérer". Mais si seules 2 colonnes sont en train de changer et disons qu'elles ne font partie d'aucun index non clusterisé, alors vous feriez mieux de "mettre à jour" les enregistrements car dans ce cas, seul l'index clusterisé sera mis à jour (et les index n'auront pas à être mis à jour ).
Sur des recherches plus poussées, j'ai trouvé que le commentaire ci-dessus par moi est en quelque sorte redondant car SQL Server dispose en interne de 2 mécanismes distincts pour effectuer une MISE À JOUR. - Une "mise à jour sur place" (c'est-à-dire en changeant une valeur de colonne en une nouvelle dans la ligne d'origine) ou comme une "MISE À JOUR non sur place" (SUPPRIMER suivie d'une INSÉRER).
Les mises à jour sur place sont la règle et sont effectuées si possible. Ici, les lignes restent exactement au même emplacement sur la même page dans la même étendue. Seuls les octets concernés sont modifiés. Le tlog n'a qu'un seul enregistrement (à condition qu'il n'y ait pas de déclencheurs de mise à jour). Les mises à jour se produisent en place si un segment de mémoire est mis à jour (et qu'il y a suffisamment d'espace sur la page). Les mises à jour se produisent également si la clé de clustering change mais que la ligne n'a pas du tout besoin de se déplacer.
Par exemple: si vous avez un index clusterisé sur le nom de famille et que vous avez les noms: Able, Baker, Charlie Maintenant, vous voulez mettre à jour Baker vers Becker. Aucune ligne ne doit être déplacée. Cela peut donc prendre place. Alors que si vous devez mettre à jour Able vers Kumar, les lignes devront être décalées (même si elles seront sur la même page). Dans ce cas, SQL Server fera une DELETE suivie d'une INSERT.
Compte tenu de ce qui précède, je vous suggère de faire une MISE À JOUR normale et de laisser SQL Server trouver la meilleure façon de le faire en interne.
Pour plus de détails sur les internes "UPDATE" ou d'ailleurs sur les internes liés à SQL Server, consultez le livre de Kalen Delaney, Paul Randal, et al. - SQL Server 2008 Internals .
Avez-vous étudié la commande MERGE dans SQL 2008? Voici un exemple de base:
merge YourBigTable ybt
using (select distinct (RecordID) from YourOtherTable) yot
on yot.Recordid = YBT.RecordID
when NOT matched by target
then insert (RecordID)
values (yot.DeviceID) ;
Il s'agit essentiellement d'une commande "UPSERT". Mettez à jour s'il existe, insérez-le si ce n'est pas le cas. Commande TRÈS rapide, très cool.
Mais j'ai moi-même vérifié la suppression et l'insertion par rapport à la mise à jour sur une table contenant 30 millions d'enregistrements (3 crores). Cette table a une clé composite unique en cluster et 3 clés non cluster. Pour Supprimer et insérer, cela a pris 9 minutes. Pour la mise à jour, il a fallu 55 minutes. Il n'y a qu'une seule colonne qui a été mise à jour dans chaque ligne.
Donc, je vous demande de ne pas deviner. Les équations changeront lorsqu'il s'agit d'un grand tableau avec de nombreuses colonnes et beaucoup de données.
La mise à jour n'est pas aussi rapide. L'astuce consiste à réaliser une insertion rapide consiste à désactiver les index pendant l'insertion des données.
Pensez à utiliser ceci:
-- disable indexes
ALTER INDEX [index_name] ON dbo.import_table DISABLE
-- ... disable more indexes
-- don't use delete if you don't care about minimal logging. truncate is faster
TRUNCATE TABLE dbo.import_table
-- just insert the new rows
INSERT dbo.import_table
SELECT
*
FROM
dbo.source_table
-- rebuild indexes
ALTER INDEX [index_name] ON dbo.import_table REBUILD
-- ... rebuild more indexes
Il est encore plus rapide de désactiver également la mise à jour automatique des statistiques dans les options de la base de données. Si la table est considérablement modifiée, vous devez exécuter:
UPDATE STATISTICS dbo.import_table
ou
EXEC sp_updatestats
comme un travail sur une base régulière (quotidienne, hebdomadaire selon la taille de la base de données) pour maintenir les statistiques à jour. La chose à surveiller est de mettre à jour les statistiques lorsque la table est vide. Cela va bousiller les statistiques si vous ne l'exécutez pas après que la table a été remplie à nouveau.