La «table vide» de SQL Server est lente après la suppression de tous (12 millions) d'enregistrements?

27

J'ai une instance SQL Server 2008 avec environ 150 colonnes. J'ai déjà rempli ce tableau avec environ 12 millions d'entrées, mais j'ai depuis effacé le tableau en préparation d'un nouvel ensemble de données.

Cependant, les commandes qui fonctionnaient autrefois instantanément sur une table vide, comme count(*)et select top 1000dans, SQL Management Studioprennent maintenant des éons pour s'exécuter.

SELECT COUNT(*) FROM TABLE_NAME 

a pris plus de 11 minutes pour renvoyer 0 et SELECT TOP 1000a mis près de 10 minutes pour renvoyer une table vide.

J'ai également remarqué que l'espace libre sur mon disque dur a littéralement disparu (de 100 à 20 G environ). La seule chose qui s'est produite entre les deux est une seule requête que j'ai exécutée:

DELETE FROM TABLE_NAME

Que se passe-t-il dans le monde?!?


la source
5
Quel modèle de récupération utilise votre base de données? S'il est "Complet", votre instance SQL stockera un enregistrement de toutes ces suppressions, ce qui pourrait être l'emplacement de votre espace libre. Si la récupération complète est une exigence, je recommande d'utiliser à la TRUNCATE TABLEplace de DELETE FROM.
Tullo_x86
2
150 colonnes? Cette table peut être saturée - la plupart des tuples devraient être beaucoup plus petits. Impossible de dire sans contexte complet, cependant.
Clockwork-Muse

Réponses:

42

On vous a déjà expliqué pourquoi TRUNCATEserait tellement plus rapide / meilleur / plus sexy que DELETE, mais il reste une question à résoudre:

Pourquoi est SELECTplus lent après avoir DELETE terminé ?

En effet, DELETEa seulement fantôme les lignes. Le tableau est tout aussi grand que lorsqu'il avait 12 millions de lignes, même s'il n'en a pas. Pour compter les lignes (0), il faut autant de temps qu'il a fallu pour compter 12 millions de lignes. Avec le temps, le processus de nettoyage des fantômes va ramasser ces enregistrements fantômes et désallouer les pages qui ne contenaient que des fantômes, et vos SELECT accéléreront. Mais en ce moment, si vous vous enregistrez, Skipped Ghosted Records/secperfmon monte probablement en flèche pendant SELECT COUNT(*). Vous pouvez également accélérer les choses par la reconstruction de la table: ALTER TABLE ... REBUILD.

TRUNCATE aurait également pris soin de ce problème, car il ne laisse aucun fantôme derrière.

Voir également À l'intérieur du moteur de stockage: nettoyage en profondeur de Ghost .

Remus Rusanu
la source
13

DELETELes instructions suppriment des lignes d'une table une par une, en enregistrant chaque ligne dans la transaction log, ainsi qu'en conservant les log sequence number (LSN)informations. Puisque vous avez mentionné que votre table contenait d'énormes données (12 millions d'enregistrements), après la suppression de laquelle votre disque dur est à court d'espace, vérifiez la taille de votre fichier journal de base de données. Il aurait très probablement grandi.

Une meilleure façon aurait été:

TRUNCATE TABLE_NAME

la source
2
+1, exactement la même chose pour Oracle DB. Si vous utilisez des instructions qui provoquent l'enregistrement des enregistrements, la base de données ralentira au fil du temps.
Petro Semeniuk
@PetroSemeniuk D'après ce dont je me souviens sur Oracle, supprimer laisse la marque des hautes eaux seule, tronquer réinitialise la marque des hautes eaux. Je crois que toutes les opérations qui nécessitent une analyse complète balayeront les blocs jusqu'à la ligne des hautes eaux. Par conséquent, la suppression peut faciliter les opérations indexées, mais pas les analyses. TRUNCATE était le bon fonctionnement.
Glenn
3

(C'était à l'origine un commentaire à la réponse de @ DaveE, mais je l'ai mis dans sa propre réponse car elle est longue)

TRUNCATE est une opération enregistrée. Il doit en être autrement, il n'est pas conforme à ACID. Cependant, les différences entre TRUNCATEet DELETE:

  • Utilisation de l'espace de TRUNCATEjournalisation : enregistre uniquement les pages / extensions * libérées, tandis que DELETEles lignes individuelles sont enregistrées.
  • Utilisation des TRUNCATEverrous : utilise généralement moins de verrous, car il faut un verrou de table et des verrous de page, par opposition à celui DELETEqui utilise des verrous de ligne **.
  • IDENTITYséquences: TRUNCATEréinitialise la séquence d'identité sur une table, si elle est présente.

(* Une extension = 8 pages. TRUNCATEEnregistrera / supprimera les extensions si elles sont toutes de cette même table, sinon elle enregistrera / supprimera les pages des extensions mixtes.

** Un effet secondaire de cela est que DELETE FROM TABLEdes pages vides peuvent potentiellement être allouées à la table, selon que l'opération peut obtenir un verrou de table exclusif ou non.)

Donc (retour à la question d'origine), TRUNCATE TABLEc'est nettement mieux que DELETE FROM TABLEsi vous videz la table mais que vous souhaitez conserver la structure (NB: TRUNCATEne peut pas être utilisé sur une table référencée par une clé étrangère d'une autre table).

Comme indiqué dans le commentaire de @ Tullo, vérifiez également le modèle de récupération de votre base de données - s'il est plein, vous devez soit commencer à prendre des sauvegardes de journaux, soit changer votre modèle de récupération en simple. Une fois que vous avez effectué l'une de ces opérations, vous souhaiterez probablement réduire votre fichier journal en tant qu'opération unique (NB: fichier journal uniquement ) afin de récupérer tout cet espace libre.

Enfin, une autre chose à savoir - les statistiques de table. exécutez UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` pour que l'optimiseur de requêtes ne soit pas gâché par les anciennes statistiques.

Simon Righarts
la source
2

(REMARQUE: je ne suis pas un DBA) DELETE est une opération enregistrée et ne libère pas l'espace utilisé. Vous disposez probablement d'un grand journal des transactions occupant de l'espace et des analyses de table s'exécutant sur l'espace table «vide». Je suppose que vous devez effacer le journal des transactions et réduire votre base de données. Cet article StackOverflow devrait vous aider à démarrer.

Et utilisez TRUNCATE TABLE lorsque vous souhaitez le faire à l'avenir.

EDIT: Ma déclaration sur TRUNCATE non connecté était en erreur. supprimé.

DaveE
la source