2010-01-26 10 views
8

Supposons que j'ai une table avec 10000000 enregistrements. Quelle est la différence entre cette solution?Supprimer une grande quantité de données dans le serveur SQL

  1. efface les données comme:

    DELETE FROM MyTable 
    
  2. supprimer toutes les données d'une rangée d'applications par ligne:

    DELETE FROM MyTable WHERE ID = @SelectedID 
    

est la première solution a une meilleure performance? quel est l'impact sur le journal et la performance?

Répondre

14

Si vous avez autant d'enregistrements dans votre tableau et que vous voulez les supprimer tous, vous devriez considérer truncate <table> au lieu de delete from <table>. Ce sera beaucoup plus rapide, mais sachez qu'il ne peut pas activer un déclencheur.

Voir pour plus de détails (ce cas serveur SQL 2000): http://msdn.microsoft.com/en-us/library/aa260621%28SQL.80%29.aspx

Suppression de la table dans l'application ligne par ligne finira dans très longtemps, que votre DBMS ne peut pas optimiser quoi que ce soit, comme il ne sait pas à l'avance, que vous allez tout supprimer.

+4

Vous pouvez annuler une troncature si vous êtes toujours dans la portée de la transaction que vous avez effectuée, contrairement à la croyance populaire qu'elle est transactionnelle pas supprimé jusqu'à la validation afin qu'il puisse être annulé en rétablissant l'IAM. – Andrew

+0

Il suffit de le lire, et vous avez raison, dans SQL Server, vous pouvez restaurer un tronqué. J'avais oracle à l'esprit où ce n'est pas possible (selon la documentation). –

+0

Je ne peux pas utiliser TRUNCATE parce que MyTable a une clé étrangère J'ai aussi besoin de la clause WHERE pour les données de filtre –

3

Le premier a clairement de meilleures performances.

Lorsque vous spécifiez DELETE [MyTable], il efface tout simplement sans vérifier l'ID. Le second perdra du temps et du fonctionnement sur le disque pour localiser un enregistrement respectif chaque fois avant de le supprimer.

Cela devient également pire parce que chaque fois qu'un enregistrement disparaît du milieu de la table, le moteur peut vouloir condenser des données sur le disque, perdant ainsi du temps et retravaillant.

Peut-être une meilleure idée serait de supprimer des données basées sur des colonnes d'index en cluster dans l'ordre décroissant. Ensuite, la table sera fondamentalement tronquée à la fin de chaque opération de suppression.

+0

s'il vous plaît me dire pourquoi. –

+0

vous dites que: "Peut-être une meilleure idée serait de supprimer les données basées sur les colonnes de l'index cluster dans l'ordre décroissant, puis la table sera fondamentalement tronquée à la fin de chaque opération de suppression." pouvez-vous décrire plus? –

+0

Le moteur de base de données alloue des données physiquement sur le disque dans l'ordre du disque en cluster. Si vous deviez supprimer des enregistrements avec les valeurs d'index les plus élevées, cela conduirait essentiellement à couper la queue du fichier, sans condenser les données qui pourraient se produire si vous supprimiez quelque chose au milieu du fichier. Ceci est particulièrement important lorsque vous ajoutez des enregistrements pour les ajouter à la fin du fichier. J'imagine que la suppression des dossiers à la fin améliorerait aussi les performances. –

3

L'option 1 va créer une transaction très importante et avoir un grand impact sur le journal/la performance, ainsi que l'escalade des verrous pour que la table ne soit pas disponible. L'option 2 sera plus lente, bien qu'elle génère moins d'impact sur le journal (en supposant que le mode bulk/full)

Si vous voulez vous débarrasser de toutes les données, Truncate Table MyTable serait plus rapide que les deux, bien qu'il ait pas de facilité pour filtrer les lignes, il fait un changement de méta-données à l'arrière et laisse tomber fondamentalement le IAM sur le sol pour la table en question.

+0

Je ne peux pas utiliser TRUNCATE parce que MyTable a une clé étrangère J'ai aussi besoin de la clause WHERE pour les données de filtre –

0

Le premier supprimera tous les données de la table et auront de meilleures performances que votre seconde qui supprimera seulement les données d'une clé spécifique.

Maintenant, si vous devez supprimer toutes les données de la table et que vous ne comptez pas sur l'utilisation de penser rollback de l'utilisation d'un truncate table

21

Si vous devez limiter à ce que les lignes que vous devez supprimer et ne pas faire une complète suppression, ou vous ne pouvez pas utiliser TRUNCATE TABLE (par exemple, la table est référencée par une contrainte FK ou inclus dans une vue indexée), alors vous pouvez faire la supprimer en morceaux:

DECLARE @RowsDeleted INTEGER 
SET @RowsDeleted = 1 

WHILE (@RowsDeleted > 0) 
    BEGIN 
     -- delete 10,000 rows a time 
     DELETE TOP (10000) FROM MyTable [WHERE .....] -- WHERE is optional 
     SET @RowsDeleted = @@ROWCOUNT 
    END 

en général, TRUNCATE est le meilleur moyen et je l'utiliserais si possible. Mais il ne peut pas être utilisé dans tous les scénarios. Notez également que TRUNCATE réinitialisera la valeur IDENTITY de la table s'il y en a une.

Si vous utilisez SQL 2000 ou une version antérieure, la condition TOP n'est pas disponible, vous pouvez donc utiliser SET ROWCOUNT à la place.

DECLARE @RowsDeleted INTEGER 
SET @RowsDeleted = 1 
SET ROWCOUNT 10000 -- delete 10,000 rows a time 

WHILE (@RowsDeleted > 0) 
    BEGIN 
     DELETE FROM MyTable [WHERE .....] -- WHERE is optional 
     SET @RowsDeleted = @@ROWCOUNT 
    END 
+2

Vous voudrez peut-être éviter l'utilisation de SET ROWCOUNT en faveur de SELECT/INSERT/UPDATE/SUPPRIMER TOP (N) ... La raison? Jetez un coup d'oeil ici: http://msdn.microsoft.com/en-us/library/ms143729.aspx et ici: https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=282528 –

+0

Bon point (en supposant SQL 2005 ou plus tard) qui est probablement un pari sûr. Mise à jour ma réponse – AdaTheDev

0

Trouvé post on Microsoft TechNet.

Fondamentalement, il recommande:

  1. En utilisant SELECT INTO, copiez les données que vous souhaitez conserver à une table intermédiaire;
  2. Tronque la table source;
  3. Recopiez avec INSERT INTO à partir de la table intermédiaire, les données dans la table source;

..

BEGIN TRANSACTION 

SELECT * 
    INTO dbo.bigtable_intermediate 
    FROM dbo.bigtable 
    WHERE Id % 2 = 0; 

    TRUNCATE TABLE dbo.bigtable; 

    SET IDENTITY_INSERT dbo.bigTable ON; 
    INSERT INTO dbo.bigtable WITH (TABLOCK) (Id, c1, c2, c3) 
    SELECT Id, c1, c2, c3 FROM dbo.bigtable_intermediate ORDER BY Id; 
    SET IDENTITY_INSERT dbo.bigtable OFF; 
ROLLBACK TRANSACTION