web-dev-qa-db-fra.com

En SQL, UPDATE est-il toujours plus rapide que DELETE + INSERT?

Disons que j'ai un tableau simple qui contient les champs suivants:

  1. ID: int, auto-incrémental (identité), clé primaire
  2. Nom: varchar (50), unique, a un index unique
  3. Tag: int

Je n'utilise jamais le champ ID pour la recherche, car mon application est toujours basée sur l'utilisation du champ Nom. 

Je dois changer la valeur du tag de temps en temps. J'utilise le code SQL trivial suivant: 

UPDATE Table SET Tag = XX WHERE Name = YY;

Je me demandais si quelqu'un savait si ce qui précède est toujours plus rapide que:

DELETE FROM Table WHERE Name = YY;
INSERT INTO Table (Name, Tag) VALUES (YY, XX);

Encore une fois - je sais que dans le deuxième exemple, l'ID est modifié, mais cela n'a pas d'importance pour mon application.

57
Roee Adler

Un peu trop tard avec cette réponse, mais comme je rencontrais une question similaire, j’ai fait un test avec JMeter et un serveur MySQL sur la même machine, où j’ai utilisé:

  1. Un contrôleur de transaction (échantillon parent générateur) contenant deux requêtes JDBC: une instruction Delete et une instruction Insert
  2. Une requête JDBC distincte contenant l'instruction de mise à jour.

Après avoir exécuté le test pour 500 boucles, j'ai obtenu les résultats suivants:

DEL + INSERT - Moyenne: 62ms

Mise à jour - Moyenne: 30ms

Résultats:  Results

56
Dyptorden

Plus la table est grande (nombre de colonnes et taille des colonnes), plus la suppression et l’insertion deviennent coûteuses, plutôt que la mise à jour. Parce que vous devez payer le prix de UNDO et REDO. DELETEs consomment plus d’espace UNDO que de UPDATE et votre REDO contient deux fois plus d’instructions que nécessaire. 

En outre, c'est tout simplement faux du point de vue des affaires. Considérez combien il serait plus difficile de comprendre une piste de vérification théorique sur cette table. 


Certains scénarios impliquent des mises à jour groupées de toutes les lignes d'une table dans lesquelles il est plus rapide de créer une nouvelle table à l'aide de CTAS à partir de l'ancienne table (en appliquant la mise à jour dans la projection de la clause SELECT), de supprimer l'ancienne table et de renommer le nouvelle table. Les effets secondaires sont la création d’index, la gestion des contraintes et le renouvellement des privilèges, mais cela mérite d’être pris en compte. 

33
APC

Une commande sur la même ligne doit toujours être plus rapide que deux sur la même ligne. Donc, la mise à jour serait mieux.

EDIT configurer la table:

create table YourTable
(YourName  varchar(50)  primary key
,Tag int
)

insert into YourTable values ('first value',1)

lancez ceci, ce qui prend 1 seconde sur mon système (SQL Server 2005):

SET NOCOUNT ON
declare @x int
declare @y int
select @x=0,@y=0
UPDATE YourTable set YourName='new name'
while @x<10000
begin
    Set @x=@x+1
    update YourTable set YourName='new name' where YourName='new name'
    SET @y=@y+@@ROWCOUNT
end
print @y

lancez ceci, ce qui a pris 2 secondes sur mon système:

SET NOCOUNT ON
declare @x int
declare @y int
select @x=0,@y=0
while @x<10000
begin
    Set @x=@x+1
    DELETE YourTable WHERE YourName='new name'
    insert into YourTable values ('new name',1)
    SET @y=@y+@@ROWCOUNT
end
print @y
11
KM.

Je crains que le corps de votre question soit sans rapport avec la question du titre. 

Si pour répondre au titre: 

En SQL, UPDATE est-il toujours plus rapide que DELETE + INSERT? 

alors répondez est NON!

Juste Google pour 

  • "Mise à jour directe coûteuse" * "serveur SQL" 
  • "mise à jour différée" * "serveur SQL" 

De telles mises à jour entraînent une réalisation plus coûteuse (plus de traitement) de la mise à jour par insertion + mise à jour que par insertion directe + mise à jour. Ce sont les cas où 

  • on met à jour le champ avec une clé unique (ou primaire) ou 
  • lorsque les nouvelles données ne tiennent pas (sont plus grandes) dans l'espace de ligne alloué avant la mise à jour (ou même dans la taille de ligne maximale), entraînant une fragmentation, 
  • etc. 

Ma recherche rapide (non exhaustive), ne prétendant pas en couvrir une, m’a donné [1], [2] 

[1]
Opérations de mise à jour
(Guide de performances et de réglage de Sybase SQL Server
Chapitre 7: L’optimiseur de requêtes SQL Server)
http://www.lcard.ru/~nail/sybase/perf/11500.htm
[2]
Les instructions UPDATE peuvent être répliquées sous forme de paires DELETE/INSERT
http://support.Microsoft.com/kb/238254

Je viens d'essayer de mettre à jour 43 champs sur une table avec 44 champs, le champ restant était la clé en cluster principale.

La mise à jour a pris 8 secondes.

Une suppression + insertion est plus rapide que l'intervalle de temps minimum que les "statistiques du client" signalent via SQL Management Studio.

Peter

MS SQL 2008

5
Peter

N'oubliez pas que la fragmentation réelle qui se produit lorsque DELETE + INSERT est émis et qu'une mise à jour correctement mise à jour fera une grande différence dans le temps.

C’est pourquoi, par exemple, REPLACE IN que MySQL implémente est déconseillé, contrairement à la syntaxe INSERT INTO ... ON DUPLICATE KEY UPDATE ....

4
jishi

Supprimer + Insérer est presque toujours plus rapide, car une mise à jour comporte beaucoup plus d'étapes.

Mettre à jour:

  1. Recherchez la ligne en utilisant PK.
  2. Lire la ligne à partir du disque.
  3. Vérifier quelles valeurs ont changé
  4. Activer le déclencheur onUpdate avec les variables remplies: NEW et: OLD
  5. Écrire de nouvelles variables sur le disque (toute la ligne)

    (Cela se répète pour chaque ligne que vous mettez à jour)

Supprimer + Insérer: 

  1. Marquer les lignes comme supprimées (uniquement dans la PK).
  2. Insérer de nouvelles lignes à la fin du tableau.
  3. Mettre à jour l'index PK avec l'emplacement des nouveaux enregistrements.

    (Cela ne se répète pas, tout peut être exécuté en un seul bloc d'opération).

Utiliser Insert + Delete fragmentera votre système de fichiers, mais pas si vite. Faire une optimisation paresseuse sur l’arrière-plan libérera toujours les blocs inutilisés et remplira la table.

4
jri

Et si vous avez quelques millions de lignes. Chaque ligne commence par une donnée, peut-être un nom de client. Lorsque vous collectez des données pour les clients, leurs entrées doivent être mises à jour. Supposons maintenant que la collection de données client est distribuée sur de nombreuses autres machines à partir de laquelle elle est ensuite collectée et placée dans la base de données. Si chaque client dispose d'informations uniques, vous ne pourrez pas effectuer de mise à jour en bloc. c'est-à-dire qu'il n'y a pas de critère where-clause à utiliser pour mettre à jour plusieurs clients en une fois. D'autre part, vous pouvez effectuer des insertions en vrac. La question pourrait donc être mieux posée comme suit: vaut-il mieux effectuer des millions de mises à jour simples ou est-il préférable de les compiler en grandes suppressions et insertions? En d'autres termes, au lieu de "update [table] set field = data où clientid = 123" plusieurs millions de fois, vous supprimez du [table] où clientid dans ([tous les clients à mettre à jour]); insérer dans [table] valeurs (données pour client1), (données pour client2), etc '

Est-ce que l'un ou l'autre choix est meilleur que l'autre, ou êtes-vous foutu dans les deux sens?

3
brian

Dans votre cas, je pense que la mise à jour sera plus rapide.

Rappelez-vous les index!

Vous avez défini une clé primaire, celle-ci deviendra probablement automatiquement un index clusterisé (du moins SQL Server le fait). Un index de cluster signifie que les enregistrements sont physiquement posés sur le disque en fonction de l'index. L'opération DELETE en elle-même ne causera pas beaucoup de problèmes, même après la suppression d'un enregistrement, l'index reste correct. Mais lorsque vous insérez un nouvel enregistrement, le moteur de base de données devra placer cet enregistrement à l'emplacement correct, ce qui, dans certaines circonstances, entraînera un "remaniement" des anciens enregistrements pour en "faire place". Là où ça va ralentir l'opération.

Un index (en particulier en cluster) fonctionne mieux si les valeurs sont en augmentation constante. Les nouveaux enregistrements sont donc simplement ajoutés à la fin. Peut-être que vous pouvez ajouter une colonne INT IDENTITY supplémentaire pour devenir un index clusterisé, cela simplifiera les opérations d'insertion.

3
user151323

Bien entendu, la réponse varie en fonction de la base de données utilisée, mais UPDATE peut toujours être implémenté plus rapidement que DELETE + INSERT. De toute façon, étant donné que les opérations en mémoire sont de toute façon plutôt triviales, une base de données basée sur un disque dur permet à UPDATE de modifier un champ de base de données sur le disque dur, tandis qu'une suppression supprime une ligne (laissant un espace vide) rangée, peut-être à la fin de la table (encore une fois, tout est dans la mise en œuvre).

L’autre problème mineur est que lorsque vous mettez à jour une seule variable dans une seule ligne, les autres colonnes de cette ligne restent les mêmes. Si vous supprimez puis effectuez une insertion, vous courez le risque d'oublier les autres colonnes et par conséquent de les laisser derrière (dans ce cas, vous devrez faire une sélection avant votre suppression pour stocker temporairement vos autres colonnes avant de les réécrire avec INSERT). .

2
erjiang

Chaque écriture dans la base de données a de nombreux effets secondaires potentiels.

Supprimer: une ligne doit être supprimée, les index mis à jour, les clés étrangères vérifiées et éventuellement supprimés en cascade, etc. ... Insertion: une ligne doit être allouée - elle peut remplacer une ligne supprimée, mais peut-être pas; les index doivent être mis à jour, les clés étrangères doivent être vérifiées, etc. .. Update: une ou plusieurs valeurs doivent être mises à jour; peut-être que les données de la ligne ne tiennent plus dans ce bloc de la base de données, il faut donc allouer plus d'espace, ce qui peut entraîner une cascade en plusieurs blocs réécrits ou conduire à des blocs fragmentés; si la valeur a des contraintes de clé étrangère, elles doivent être vérifiées, etc.

Pour un très petit nombre de colonnes ou si toute la ligne est mise à jour, la suppression + insertion est peut-être plus rapide, mais le problème de la contrainte FK est important. Bien sûr, vous n’avez peut-être pas de contraintes sur le FK maintenant, mais est-ce que cela sera toujours vrai? Et si vous avez un déclencheur, il est plus facile d'écrire du code qui gère les mises à jour si l'opération de mise à jour est vraiment une mise à jour.

Un autre problème à prendre en compte est que, parfois, l'insertion et la suppression conservent des verrous différents de ceux de la mise à jour. La base de données peut verrouiller la table entière lors de l'insertion ou de la suppression, au lieu de simplement verrouiller un seul enregistrement lors de la mise à jour de cet enregistrement.

À la fin, je suggérerais simplement de mettre à jour un enregistrement si vous voulez le mettre à jour. Vérifiez ensuite les statistiques de performances de votre base de données et celles de cette table pour voir si des améliorations de performances doivent être apportées. Tout le reste est prématuré.

Voici un exemple tiré du système de commerce électronique sur lequel je travaille: nous avons stocké les données de transaction de carte de crédit dans la base de données selon une approche en deux étapes: tout d'abord, écrivez une transaction partielle pour indiquer que nous avons démarré le processus. Ensuite, lorsque les données d'autorisation sont renvoyées par la banque, mettez à jour l'enregistrement. Nous aurions pu supprimer puis réinsérer l'enregistrement mais nous avons simplement utilisé update. Notre administrateur de base de données nous a indiqué que la table était fragmentée, car la base de données n'allouait qu'une petite quantité d'espace pour chaque ligne et que la mise à jour entraînait un chaînage des blocs car elle ajoutait beaucoup de données. Cependant, plutôt que de basculer sur DELETE + INSERT, nous avons juste ajusté la base de données pour toujours allouer la ligne entière. Cela signifie que la mise à jour pourrait utiliser l'espace vide pré-alloué sans aucun problème. Aucun changement de code requis, et le code reste simple et facile à comprendre.

1

Cela dépend du produit. Un produit peut être implémenté pour convertir (sous la couverture) toutes les mises à jour en fichiers DELETE et INSERT (enveloppés dans une transaction). Sous réserve que les résultats soient cohérents avec la sémantique de UPDATE.

Je ne dis pas que je suis au courant de tout produit qui fait cela, mais c'est parfaitement légal.

1

La question de la vitesse est sans importance sans problème de vitesse spécifique.

Si vous écrivez du code SQL pour modifier une ligne existante, vous la mettez à jour. Tout le reste est incorrect.

Si vous voulez enfreindre les règles de fonctionnement du code, vous feriez bien d'avoir une sacrée bonne raison quantifiée, et non une vague idée de "Cette façon de faire est plus rapide", quand vous n'en avez pas. idée de ce que "plus vite" est.

1
Andy Lester

Dans des cas spécifiques, Supprimer + Insérer vous ferait gagner du temps. J'ai une table qui a 30000 lignes impaires et il y a une mise à jour/insertion quotidienne de ces enregistrements en utilisant un fichier de données. Le processus de téléchargement génère 95% des instructions de mise à jour car les enregistrements sont déjà présents et 5% des insertions pour celles qui n'existent pas. Vous pouvez également télécharger les enregistrements du fichier de données dans une table temporaire, supprimer la table de destination des enregistrements de la table temporaire, puis insérer celle-ci à partir de la table temporaire et afficher un gain de temps de 50%.

0
shan