0
votes

Existe-t-il une bibliothèque comme SqlBulkCopy pour supprimer un grand nombre de lignes en C # et SQL Server?

En utilisant SqlBulkCopy je peux insérer un grand nombre de lignes en C # dans SQL Server, ce qui est vraiment très rapide. J'ai besoin d'une chose similaire pour les opérations de suppression.

Existe-t-il quelque chose de disponible qui effectuera une opération de suppression plus rapide et plus performante en C #? L'utilisation d'une procédure stockée avec une liste d'ID de ligne en tant que paramètre n'est pas un bon moyen. L'appel à plusieurs reprises de la procédure stockée n'est pas non plus une bonne idée. Alors, quelle est la meilleure idée?

J'ai besoin de supprimer environ 30k lignes d'une table.


8 commentaires

EntityFramework-extensions est une bibliothèque qui peut être utilisée pour des opérations en bloc comme celle-ci - entityframework-extensions.net/bulk-delete


La suppression de 30 000 lignes dans une table SQL Server est un travail pour une requête DELETE ordinaire, et c'est déjà le moyen le plus rapide possible. Trouvez une clause WHERE qui englobe adéquatement vos 30 000 enregistrements.


Seulement 30k? Quel genre de performance voyez-vous pour le faire dans un seul? Quel type de performance pour le regrouper en 3x10k ou 6x5k suppressions? ps, si vous voulez vider une table, tronquez-la


Vous pouvez créer un type de données défini par l'utilisateur tel que "IntegerTable", le remplir côté client, le transmettre à une procédure stockée qui a accepté un "IntegerTable" et émettre un DELETE FROM Target INNER JOIN'ed sur @IntegerTable. Ou si vous utilisez EF, Adam T a publié un excellent exemple ci-dessus.


Le moyen le plus rapide de supprimer des lignes est d'utiliser une clé primaire afin que la recherche de chaque ligne soit rapide. Vous ne voulez probablement pas faire cela à partir de c # car l'interface entre c # et SQL Server ajoutera du temps. J'utiliserais donc SQLcmd.exe ou Power Shell (qui a SQLcmd.exe intégré). Consultez les utilitaires de ligne de commande: docs.microsoft.com/en-us/sql/tools/… . Vous pouvez exécuter la méthode à partir de l'application ac #.


Je sais que ce n'est pas beaucoup de temps, mais dans mon cas, c'est beaucoup de temps. L'utilisateur télécharge un fichier avec 30k lignes, après les avoir traités, je dois supprimer ces lignes de la table et je dois fournir un commentaire. Je dois donc le faire avec un minimum de temps. À l'heure actuelle, cela prend presque une minute alors que la méthode d'insertion sqlbulkcopy ne prend que quelques secondes à insérer.


Marquez les enregistrements téléchargés d'une manière quelconque afin que, lorsque vous êtes prêt à les supprimer, vous puissiez simplement exécuter une requête DELETE pour ces enregistrements O la marque existe.


Si vos enregistrements sont horodatés lorsque vous les insérez en bloc, vous pouvez simplement filtrer sur l'horodatage dans la requête DELETE.


5 Réponses :


1
votes

Vous pouvez créer un tableau supplémentaire avec une colonne pour vos ID cibles, et peut-être aussi un ID de travail. Ensuite, vous pouvez insérer vos identifiants dans ce tableau. Vous vous retrouverez avec environ 30 000 lignes dans le nouveau tableau: une pour chaque ID à supprimer. Si les ID de votre table ne sont pas la clé primaire, c'est également le moment d'effectuer cette traduction. Vous pouvez laisser cette partie de l'opération être un peu lente si vous en avez besoin, car elle n'interférera pas avec d'autres parties de votre base de données en termes de verrous, ou vous pouvez utiliser une technique d'insertion en masse, avec laquelle vous semblez déjà à l'aise.

Une fois cette table remplie, vous pouvez écrire une instruction DELETE qui inclut un JOIN dans cette nouvelle table . D'après mon expérience, ce sera le moyen le plus rapide de terminer votre opération de suppression.

Cela ne ressemble pas à votre situation, mais lorsque vous en avez vraiment besoin pour s'exécuter plus rapidement, vous pouvez également essayer d'exécuter le travail pendant une période de faible charge, ou si vous avez une fenêtre de maintenance, vous pouvez passer à la journalisation en masse pendant un certain temps, bien que ce soit une option de dernier recours.

Une fois la requête terminée, tronquez la table supplémentaire ou supprimez les lignes avec votre ID de travail.

Si ce n'est toujours pas assez rapide, vous pouvez encore améliorer les choses en implémentant des suppressions logiques dans votre application. Une suppression logique se produit lorsque vous ajoutez une colonne dans la table avec un nom tel que IsDeleted ou DeletedDate . Ensuite, pour supprimer une ligne, il vous suffit de mettre à jour la valeur de cette colonne. Vous pouvez également avoir un processus distinct qui s'exécute en arrière-plan pour nettoyer ces enregistrements après un certain temps si vous le souhaitez.

Les suppressions logiques peuvent être beaucoup plus rapides pour traiter des lots plus volumineux. Cependant, cela peut impliquer de réécrire des parties importantes de votre application pour comprendre la différence entre un enregistrement supprimé et un enregistrement actif.


1 commentaires

Je pense aussi à quelque chose comme ça.



0
votes

Vous pouvez utiliser l'instruction MERGE pour supprimer massivement des données dans SQL Server.

Vous devez spécifier les clés primaires de la table que vous souhaitez supprimer et la faire correspondre à votre table réelle. Ensuite, vous pouvez décider quoi faire avec les enregistrements correspondants ou non correspondants, dans le cas où vous les supprimez en cas de correspondance:

create table MyTable ( id int primary key, data varchar(5) )
insert into MyTable values (1, 'a'), (2, 'b'), (3, 'c')

merge MyTable as t
using
(
    select * from
    (
        values (1), (2)
    ) V(id)
) as x
on x.id = t.id
when matched then delete;

select * from MyTable -- only pk 3 left

Cela fonctionne très bien lors de la suppression d'une grande quantité de données et il est assez facile à implémenter en C #, bien qu'il n'ait pas les mêmes performances que SqlBulkCopy .

MERGE documents: https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql


0 commentaires

0
votes

Je réutiliserais normalement un type de table personnalisé dans le cadre d'un ensemble CRUD étendu de procédures stockées lorsque cette situation se produit.

DECLARE @RecordCount INT = 100000
;
WITH R1(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(10))dt(n)),
R2(N) AS (SELECT 1 FROM R1 a, R1 b),
R3(N) AS (SELECT 1 FROM R2 a, R2 b), 
R4(N) AS (SELECT 1 FROM R3 a, R3 b),
Tally(Number) AS (SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM R4)

INSERT
INTO _DeleteTest
SELECT Number,'Hey' FROM Tally
WHERE
    Number<=100000

DECLARE @T TABLE(ID INT)
INSERT INTO @T SELECT ID FROM _DeleteTest

DELETE D
FROM _DeleteTest D
INNER JOIN @T P ON P.ID=D.ID


(100000 rows affected)

(100000 rows affected)

(100000 rows affected)

Completion time: 2020-11-13T13:53:54.2883938-05:00

Bien sûr, le kilométrage peut varier en fonction du nombre et des types d'index et de l'occupation du serveur. J'ai couru ceci contre un serveur assez chargé. J'ai défini le seuil maximum à 100K enregistrements et il a construit les données et effectué l'opération de suppression en moins d'une seconde.

CREATE PROCEDURE MyTableDeletByPrimaryKeyInBulk(@PrimaryKeyTable IntegerIDTable)
AS 
    DELETE D
    FROM MyTable D
    INNER JOIN @PrimaryKeyTable P ON P.ID=D.TableID


3 commentaires

Vous feriez cela pour 30K suppressions? Comment les performances se comparent-elles à la simple utilisation de DELETE, par exemple 30 instructions de suppression spécifiant chacune 1000 clés primaires à supprimer? Cela semble être une complexité inutile. En plus d'être plus simple et probablement tout aussi rapide, le code qui utilise des instructions de suppression ordinaires est indépendant de la base de données.


Cela démontre un moyen d'obtenir 30K + PK dans la base de données. Une fois sur place, la suppression des enregistrements peut être effectuée comme bon vous semble. Par souci de concision, j'ai omis tout code qui implique des tables intermédiaires et un travail SQL, des files d'attente ETL ou tout appareil similaire, car je pensais que c'était un peu hors de portée pour une question de suppression en bloc.


@Eric J. -30K n'est pas vraiment un très grand nombre à supprimer. Dans certains cas, je vais augmenter la taille de mon lot d'insertions en vrac à 15K et en tirer un plus grand coup de pouce que d'utiliser quelque chose de normal comme 1000.



0
votes

Je ne me souviens pas de voir un BulkDelete, mais selon [Microsoft] [1] https://social.technet.microsoft.com/wiki/contents/articles/20651.sql-server-delete-a-huge-amount-of- data-from-a-table.aspx [1]:

Vous appliquez simplement une table tronquée TableName, c'est comme un Bulk et videz tous les enregistrements de la table, si ce n'est pas comme ça, suivez les conseils précédents de @ Phate01


1 commentaires

Ce serait très bien si vous vouliez supprimer tous les enregistrements de la table, cependant, si vous vouliez supprimer 100 enregistrements sur 1000, tronquer ne serait pas une solution appropriée.



0
votes

Utiliser simplement une suppression plus petite dans la boucle fonctionne pour moi dans le scénario «grande suppression»

plus: cela ne verrouille pas toute la table pendant une longue période.

inconvénients: aucun avantage si utilisé en une seule transaction

--declare @i int =0
SELECT NULL --Makes the WHILE loop work.
WHILE @@ROWCOUNT <> 0
BEGIN
    --set @i=@i+1
    --print(@i)
    DELETE TOP (5000) FROM yourtable 
    WHERE ...
    
END

30K est un petit nombre de lignes pour SQL, je l'utilise pour supprimer des millions de lignes dans une table énorme.

Coluld être un autre problème comme une mauvaise indexation, verrouillage, table de tas ECC.


0 commentaires