web-dev-qa-db-fra.com

L'instruction de suppression en SQL est très lente

J'ai des déclarations comme celle-ci qui arrivent à expiration:

DELETE FROM [table] WHERE [COL] IN ( '1', '2', '6', '12', '24', '7', '3', '5')

J'ai essayé de faire un à la fois comme ça:

DELETE FROM [table] WHERE [COL] IN ( '1' )

et jusqu'à présent, il est à 22 minutes et continue.

Le tableau contient 260 000 lignes et quatre colonnes.

Quelqu'un at-il une idée de la raison pour laquelle cela serait si lent et comment l'accélérer? J'ai un index non unique, non-cluster sur le [COL] sur lequel je fais le WHERE. J'utilise SQL Server 2008 R2

mise à jour: je n'ai aucun déclencheur sur la table.

66
Kyle

Ce qui peut ralentir une suppression:

  • supprimer beaucoup d'enregistrements
  • beaucoup d'index
  • index manquants sur les clés étrangères dans les tables enfants. (merci à @CesarAlvaradoDiaz d'avoir mentionné cela dans les commentaires)
  • impasses et blocage
  • déclencheurs
  • suppression en cascade (ces dix enregistrements parents que vous supprimez pourraient signifier la suppression de millions d'enregistrements enfants)
  • Le journal des transactions doit grandir
  • Beaucoup de clés étrangères à vérifier

Vous devez donc déterminer ce qui bloque et le réparer ou exécuter les suppressions en dehors des heures où ils ne gêneront pas la charge de production normale. Vous pouvez exécuter la suppression par lots (utile si vous avez des déclencheurs, une suppression en cascade ou un grand nombre d'enregistrements). Vous pouvez supprimer et recréer les index (mieux si vous pouvez le faire aussi en dehors des heures de travail).

73
HLGEM
  1. Désactiver CONSTRAINT

    ALTER TABLE [TableName] NOCHECK CONSTRAINT ALL;

  2. Désactiver l'index

    ALTER INDEX ALL ON [TableName] DISABLE;

  3. Reconstruire l'index

    ALTER INDEX ALL ON [TableName] REBUILD;

  4. Activer CONTRAINT

    ALTER TABLE [TableName] CHECK CONSTRAINT ALL;

  5. Supprimer à nouveau

49
Shahab J

La suppression de nombreuses lignes peut être très lente. Essayez de supprimer quelques-uns à la fois, comme:

delete top (10) YourTable where col in ('1','2','3','4')
while @@rowcount > 0
    begin
    delete top (10) YourTable where col in ('1','2','3','4')
    end
18
Andomar

Action préventive

Vérifiez à l'aide de SQL Profiler pour la cause première de ce problème. Il se peut que Triggers soit à l'origine du retard d'exécution. Cela peut être n'importe quoi. N'oubliez pas de sélectionner le Database Name et Object Name lors du démarrage de Trace pour exclure l'analyse des requêtes inutiles ...

Filtrage des noms de bases de données

Filtrage de noms de tables de procédures stockées/déclencheurs

Action corrective

Comme vous l'avez dit, votre table contient 260 000 enregistrements ... et IN Predicate contient six valeurs. Maintenant, chaque enregistrement est recherché 260 000 fois pour chaque valeur dans IN Predicate. Au lieu de cela, il devrait s'agir de la jointure interne, comme ci-dessous ...

Delete K From YourTable1 K
Inner Join YourTable2 T on T.id = K.id

Insérer le IN Predicate valeurs dans un Temporary Table ou Local Variable

4
user1425057

Si la table que vous supprimez a des déclencheurs BEFORE/APRES EFFACER, il se peut que quelque chose s'y trouvant puisse provoquer votre retard.

De plus, si vous avez des clés étrangères référençant cette table, des UPDATE ou DELETE supplémentaires peuvent se produire.

3
sybkar

Il est possible que d'autres tables aient une contrainte FK pour votre [table]. La base de données doit donc vérifier ces tables pour maintenir l'intégrité référentielle. Même si vous avez tous les index nécessaires correspondant à ces FK, vérifiez leur montant.

J'ai eu la situation quand NHibernate créé incorrectement FK dupliqué s sur les mêmes colonnes, mais avec des noms différents (ce qui est autorisé par SQL Server). Il a considérablement ralenti l'exécution de l'instruction DELETE.

2
flam3

Dans mon cas, les statistiques de la base de données avaient été corrompues. La déclaration

delete from tablename where col1 = 'v1' 

prenait 30 secondes même s’il n’y avait pas d’enregistrement correspondant mais

delete from tablename where col1 = 'rubbish'

a couru instantanément

fonctionnement

update statistics tablename

corrigé le problème

1
Mike

Si vous supprimez tous les enregistrements de la table plutôt que quelques-uns, il peut être beaucoup plus rapide de simplement supprimer et recréer la table.

0
lastlink

[COL] est-il vraiment un champ de caractères contenant des chiffres ou pouvez-vous vous débarrasser des guillemets simples autour des valeurs? @Alex a raison, IN est plus lent que =, donc si vous pouvez le faire, vous serez mieux loti:

DELETE FROM [table] WHERE [COL] = '1'

Mais il vaut mieux utiliser des nombres plutôt que des chaînes pour trouver les lignes (SQL aime les nombres):

 DELETE FROM [table] WHERE [COL] = 1

Peut-être essayer:

 DELETE FROM [table] WHERE CAST([COL] AS INT) = 1

Dans les deux cas, assurez-vous de disposer d'un index sur la colonne [COL] pour accélérer l'analyse de la table.

0
Russell Fox

J'ai lu cet article, c'était vraiment utile pour résoudre tout type d'inconvénient

https://support.Microsoft.com/en-us/kb/22445

c'est un cas de waitresource KEY: 16: 72057595075231744 (ab74b4daaf17)

-- First SQL Provider to find the SPID (Session ID)

-- Second Identify problem, check Status, Open_tran, Lastwaittype, waittype, and waittime
-- iMPORTANT Waitresource select * from sys.sysprocesses where spid = 57

select * from sys.databases where database_id=16

-- with Waitresource check this to obtain object id 
select * from sys.partitions where hobt_id=72057595075231744

select * from sys.objects where object_id=2105058535
0
Eduardo

Vérifiez le plan d'exécution de cette instruction de suppression. Jetez un coup d'oeil si index chercher est utilisé. Aussi, quel est le type de données de col?

Si vous utilisez un type de données incorrect, changez l'instruction update (comme de '1' à 1 ou N'1 ').

Si l'analyse d'index est utilisée, envisagez d'utiliser indice de requête ..

0
Jānis

Après avoir inspecté un package SSIS (en raison de l’exécution très lente de commandes par SQL Server), configuré dans un de nos clients environ 5 ou 4 ans avant le moment où j’écrivais cela, j’ai découvert qu’il existait les tâches ci-dessous: 1 ) insérez les données d’un fichier XML dans une table appelée [Importbarcdes].

2) commande de fusion sur une autre table cible, en utilisant comme source la table susmentionnée.

3) "supprimer de [Importbarcodes]", pour effacer le tableau de la ligne insérée après la lecture du fichier XML par la tâche du package SSIS.

Après une inspection rapide, toutes les instructions (SELECT, UPDATE, DELETE, etc.) de la table ImportBarcodes, qui ne comportait qu'une seule ligne, prenaient environ 2 minutes.

Les événements étendus ont affiché beaucoup de notifications d’attente PAGEIOLATCH_EX.

Aucun index de la table n'était présent et aucun déclencheur n'a été enregistré.

Lors de l’examen approfondi des propriétés de la table, dans l’onglet Stockage et dans la section générale, le champ Espace de données affichait plus de 6 GIGABYTES d’espace alloué en pages.

Qu'est-il arrivé:

La requête a fonctionné pendant une bonne partie de la journée chaque jour au cours des 4 dernières années, insérant et supprimant des données dans la table, laissant les fichiers d'échange inutilisés sur place sans les libérer.

C'est donc la raison principale des événements d'attente capturés par la session d'événements étendus et des commandes exécutées lentement sur la table.

Fonctionnement ALTER TABLE ImportBarcodes REBUILD résolu le problème libérant tout l'espace inutilisé. TRUNCATE TABLE ImportBarcodes a fait la même chose, avec la seule différence de supprimer tous les fichiers de page et toutes les données.

0
jimas13