2017-02-08 2 views
1

Je souhaite supprimer 10 Go (1%) de données de la table 1TB. J'ai trouvé plusieurs articles pour supprimer de grandes quantités de données d'une énorme table, mais je n'ai pas trouvé grand-chose sur la suppression d'un plus petit pourcentage de données d'une énorme table.Comment supprimer efficacement un petit ensemble de données d'une grande table SQL

Détails supplémentaires: Vous essayez de supprimer les données du bot du tableau des visites. La condition de filtre est une combinaison de champs ... ip (liste des ips environ 20 d'entre eux) et useragent comme « % CHOSE% »

taille de useragent 1024 varchar

Les données peuvent être anciennes ou nouvelles. Je ne peux pas utiliser le filtre de date

+2

Utiliser un filtre spécifique sans doute. Expliquez-en davantage que ce que vous essayez de faire. – Rahul

+0

Même concept. Supprimez-le par lots. –

+0

Comme le dit @Rahul, tant que le champ de condition a index vous devriez être ok. Sinon, dites-nous ce que vous avez essayé et quel est le problème. –

Répondre

1

Voici une suppression de lot par morceaux que j'utilise régulièrement. Peut-être que cela vous donnerait quelques idées sur la façon d'aborder votre besoin. Je crée un proc stocké et appelle le proc à partir d'un travail d'agent SQL. Je le programme généralement pour permettre une sauvegarde du journal des transactions entre les exécutions afin que le journal ne devienne pas trop volumineux. Vous pouvez toujours l'exécuter de manière interactive si vous le souhaitez.

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 


CREATE PROC [DBA_Delete_YourTableName] AS 



SET NOCOUNT ON; 
--------------------------------------------------------- 
DECLARE @DaysHistoryToKeep INT 
SET @DaysHistoryToKeep = 90 

IF @DaysHistoryToKeep < 30 
SET @DaysHistoryToKeep = 30 
--------------------------------------------------------- 

DECLARE @continue INT 
DECLARE @rowcount INT 
DECLARE @loopCount INT 
DECLARE @MaxLoops INT 

DECLARE @TotalRows BIGINT 
DECLARE @PurgeThruDate DATETIME 

SET @PurgeThruDate = DATEADD(dd,(-1)*(@DaysHistoryToKeep+1), GETDATE()) 

SET @MaxLoops = 100 
SET @continue = 1 
SET @loopCount = 0 

SELECT @TotalRows = (SELECT COUNT(*) FROM YourTableName (NOLOCK) WHERE CREATEDDATETIME < @PurgeThruDate) 
PRINT 'Total Rows = ' + CAST(@TotalRows AS VARCHAR(20)) 
PRINT '' 

WHILE @continue = 1 
BEGIN 
    SET @loopCount = @loopCount + 1 
    PRINT 'Loop # ' + CAST(@loopCount AS VARCHAR(10)) 
    PRINT CONVERT(VARCHAR(20), GETDATE(), 120) 

    BEGIN TRANSACTION 
     DELETE TOP (4500) YourTableName WHERE CREATEDDATETIME < @PurgeThruDate 
     SET @rowcount = @@rowcount 
    COMMIT 

    PRINT 'Rows Deleted: ' + CAST(@rowcount AS VARCHAR(10)) 
    PRINT CONVERT(VARCHAR(20), GETDATE(), 120) 
    PRINT '' 

    IF @rowcount = 0 OR @loopCount >= @MaxLoops 
    BEGIN 
     SET @continue = 0 
    END 
END 

SELECT @TotalRows = (SELECT COUNT(*) FROM YourTableName (NOLOCK) WHERE CREATEDDATETIME < @PurgeThruDate) 
PRINT 'Total Rows Remaining = ' + CAST(@TotalRows AS VARCHAR(20)) 
PRINT '' 


GO 
1

L'état du filtre est ... ip (liste des ips environ 20 d'entre eux) et useragent comme '% CHOSE%'

En ce qui concerne la taille de la table, il est important de toucher comme quelques lignes que possible lors de l'exécution de la suppression.

  1. J'imagine sur une table taille que vous avez déjà un index sur la colonne ip. Cela peut aider (ou non) à mettre votre liste de 20 ou plus dans une table au lieu d'une clause in, surtout s'il s'agit de paramètres. Je regarderais mon plan de requête pour voir. J'espère que useragent like '%SOMETHING%' est habituellement vrai;Dans le cas contraire, il s'agit d'un test coûteux, car SQL Server doit examiner chaque ligne pour rechercher un élément ip éligible. Sinon, une refonte pour permettre à la requête d'éviter like serait probablement bénéfique.

[D] eleting plus petit pourcentage est pas vraiment pertinent. L'utilisation de critères de recherche sélectifs est (comme ci-dessus), tout comme la taille de la transaction de suppression en absolus termes. Par définition, la taille de la suppression en termes de lignes et de taille de ligne détermine la taille de la transaction. De très grosses transactions peuvent pousser contre les ressources de la machine. En les cassant en petits, on obtient de meilleures performances dans de tels cas.

Le dernier serveur que j'avais utilisé avait 0,25 To RAM et était confortable en supprimant 1 million de lignes à la fois, mais pas 10 millions. Votre kilométrage variera; vous devez essayer, et observer, pour voir.

Combien vous êtes prêt à taxer la machine dépendra de ce qui est (ou doit être capable de) fonctionner en même temps. La façon dont vous divisez une action logique - supprimez toutes les lignes où [condition] - en "morceaux" dépend aussi de ce que vous voulez que la base de données ressemble pendant que la procédure de suppression est en cours, lorsque certains morceaux sont supprimés et d'autres restent présent.

Si vous décidez de le casser en morceaux, je recommande pas en utilisant un nombre fixe de lignes et une syntaxe TOP(n), parce que la solution est moins logique. Sauf si vous utilisez order by, vous laissez au serveur de choisir arbitrairement quelles lignes N à supprimer. Si vous utilisez order by, vous demandez au serveur de trier le résultat avant de commencer la suppression, éventuellement plusieurs fois au cours de la totalité du cycle. Bleh! Au lieu de cela, recherchez un sous-ensemble logique de lignes, idéalement identifiables le long de l'index cluster, qui se situent sous le seuil de votre machine d'un nombre acceptable de lignes à supprimer en même temps. Boucle sur cet ensemble. Dans votre cas, je serais tenté de parcourir l'ensemble des valeurs ip dans la clause in. Au lieu de delete ... where ip in(...), vous obtenez (à peu près) for each ip delete ... where ip = @ip

L'avantage de cette dernière approche est que vous savez toujours où se trouve la base de données. Si vous tuez la procédure ou qu'elle est annulée à mi-chemin à travers son itération, vous pouvez examiner la base de données pour voir quels sont les ips qui restent (ou quels que soient les critères que vous finissez par utiliser). Vous évitez tout type de comportement pathologique, dans lequel une requête obtient un résultat partiel car une partie de vos critères de sélection (déterminés par le serveur seul) sont présents et d'autres supprimés. En pensant au problème, vous pouvez dire, Je suis incapable de supprimer l'adresse IP 192.168.0.1 parce que, sans se demander quelle partie a déjà été supprimée.

En résumé, je recommande:

  • Donnez le serveur toutes les chances de ne toucher que les lignes que vous souhaitez affecter, et vérifier c'est ce qu'il va faire.
  • Construisez votre routine de suppression, si vous en avez besoin, pour supprimer les blocs logiques, de sorte que vous puissiez raisonner sur l'état de la base de données à tout moment.