web-dev-qa-db-fra.com

Pourquoi les insertions / mises à jour par lots sont-elles plus rapides? Comment fonctionnent les mises à jour par lots?

Pourquoi les insertions par lots sont-elles plus rapides? Est-ce parce que la surcharge de connexion et de configuration pour l'insertion d'une seule ligne est la même pour un ensemble de lignes? Quels autres facteurs accélèrent l'insertion de lots?

Comment fonctionnent les mises à jour par lots? En supposant que la table n'a pas de contraintes d'unicité, les instructions d'insertion n'ont pas vraiment d'effet sur les autres instructions d'insertion du lot. Cependant, lors des mises à jour par lots, une mise à jour peut modifier l'état de la table et peut donc affecter le résultat d'autres requêtes de mise à jour dans le lot.

Je sais que les requêtes d'insertion par lots ont une syntaxe où vous avez toutes les valeurs d'insertion dans une grande requête. À quoi ressemblent les requêtes de mise à jour par lots? Par exemple si j'ai des requêtes de mise à jour unique du formulaire:

update <table> set <column>=<expression> where <condition1>
update <table> set <column>=<expression> where <condition2>
update <table> set <column>=<expression> where <condition3>
update <table> set <column>=<expression> where <condition4>

Que se passe-t-il lorsqu'ils sont utilisés dans un lot. À quoi ressemblera la requête unique?

Et les insertions et mises à jour par lots font-elles partie de la norme SQL?

37
letronje

Pourquoi les insertions par lots sont-elles plus rapides?

Pour de nombreuses raisons, mais les trois principales sont les suivantes:

  • La requête n'a pas besoin d'être analysée à nouveau.
  • Les valeurs sont transmises en un aller-retour au serveur
  • Les commandes sont dans une seule transaction

Est-ce parce que la surcharge de connexion et de configuration pour l'insertion d'une seule ligne est la même pour un ensemble de lignes?

En partie oui, voir ci-dessus.

Comment fonctionnent les mises à jour par lots?

Cela dépend de RDBMS.

Dans Oracle, vous pouvez transmettre toutes les valeurs sous forme de collection et utiliser cette collection comme table dans un JOIN.

Dans PostgreSQL et MySQL, vous pouvez utiliser la syntaxe suivante:

INSERT
INTO    mytable
VALUES 
        (value1),
        (value2),
        …

Vous pouvez également préparer une requête une seule fois et l'appeler dans une sorte de boucle. Il existe généralement des méthodes pour ce faire dans une bibliothèque cliente.

En supposant que la table n'a pas de contraintes d'unicité, les instructions d'insertion n'ont pas vraiment d'effet sur les autres instructions d'insertion du lot. Mais, lors des mises à jour par lots, une mise à jour peut modifier l'état de la table et peut donc affecter le résultat d'autres requêtes de mise à jour dans le lot.

Oui, et vous pouvez ou non bénéficier de ce comportement.

Je sais que les requêtes d'insertion par lots ont une syntaxe où vous avez toutes les valeurs d'insertion dans une grande requête. À quoi ressemblent les requêtes de mise à jour par lots?

Dans Oracle, vous utilisez la collection dans une jointure:

MERGE
INTO    mytable
USING   TABLE(:mycol)
ON      …
WHEN MATCHED THEN
UPDATE
SET     …

Dans PostgreSQL:

UPDATE  mytable
SET     s.s_start = 1
FROM    (
        VALUES
        (value1),
        (value2),
        …
        ) q
WHERE   …
27
Quassnoi

Je cherchais une réponse sur le même sujet, à propos de la mise à jour "bulk/batch". Les gens décrivent souvent le problème en le comparant à une clause d'insertion avec plusieurs ensembles de valeurs (la partie "en bloc").

INSERT INTO mytable (mykey, mytext, myint)
VALUES 
  (1, 'text1', 11),
  (2, 'text2', 22),
  ...

Une réponse claire m'évitait toujours, mais j'ai trouvé la solution ici: http://www.postgresql.org/docs/9.1/static/sql-values.html

Pour être clair:

UPDATE mytable
SET 
  mytext = myvalues.mytext,
  myint = myvalues.myint
FROM (
  VALUES
    (1, 'textA', 99),
    (2, 'textB', 88),
    ...
) AS myvalues (mykey, mytext, myint)
WHERE mytable.mykey = myvalues.mykey

Il a la même propriété d'être "en vrac" aka contenant beaucoup de données avec une seule instruction.

26
Qerr

Les autres articles expliquent pourquoi les instructions en bloc sont plus rapides et comment le faire avec des valeurs littérales.

Je pense qu'il est important de savoir comment le faire avec des espaces réservés. Ne pas utiliser d'espaces réservés peut conduire à des chaînes de commandes gigantesques, à des citations/échappements de bogues et donc à des applications sujettes à l'injection SQL.

Insertion en masse avec des espaces réservés dans PostgreSQL> = 9.1

Pour insérer un nombre arbitraire de lignes dans la table "mytable", composée des colonnes "col1," col2 "et" col3 ", tout en un est obtenu (une instruction, une transaction):

INSERT INTO mytable (col1, col2, col3)
 VALUES (unnest(?), unnest(?), unnest(?))

Vous devez fournir trois arguments à cette déclaration. La première doit contenir toutes les valeurs de la première colonne et ainsi de suite. Par conséquent, tous les arguments doivent être des listes/vecteurs/tableaux de longueur égale.

Mise à jour en masse avec des espaces réservés dans PostgreSQL> = 9.1

Disons que votre table s'appelle "mytable". Il se compose des colonnes "clé" et "valeur".

update mytable 
  set value = data_table.new_value
  from 
    (select unnest(?) as key, unnest(?) as new_value) as data_table
  where mytable.key = data_table.key

Je sais, ce n'est pas facile à comprendre. Cela ressemble à du SQL obscurci. De l'autre côté: cela fonctionne, il évolue, il fonctionne sans aucune concaténation de chaîne, il est sûr et il est extrêmement rapide.

Vous devez fournir deux arguments à cette instruction. Le premier doit être une liste/vecteur/tableau qui contient toutes les valeurs de la colonne "clé". Bien entendu, le second doit contenir toutes les valeurs de la colonne "valeur".

Si vous atteignez des limites de taille, vous devrez peut-être examiner COPY INTO ... FROM STDIN (PostgreSQL).

4
hagello

Dans une mise à jour par lots, la base de données fonctionne par rapport à un ensemble de données, dans une mise à jour ligne par ligne, elle doit exécuter la même commande autant de fois qu'il y a de lignes. Donc, si vous insérez un million de lignes dans un lot, la commande est envoyée et traitée une fois et dans une mise à jour ligne par ligne, elle est envoyée et traitée un million de fois. C'est aussi pourquoi vous ne souhaitez jamais utiliser un curseur dans SQL Server ou une sous-requête corrélée.

un exemple de mise à jour basée sur un ensemble dans SQL Server:

update mytable
set myfield = 'test'
where myfield is null

Cela mettrait à jour tous les 1 million d'enregistrements qui sont nuls en une seule étape. Une mise à jour du curseur (qui est la façon dont vous mettriez à jour un million de lignes de manière non batch) parcourrait chaque ligne une fois et la mettrait à jour.

Le problème avec un insert de lot est la taille du lot. Si vous essayez de mettre à jour trop d'enregistrements à la fois, la base de données peut verrouiller la table pendant la durée du processus, bloquant ainsi tous les autres utilisateurs. Vous devrez donc peut-être effectuer une boucle qui ne prend qu'une partie du lot à la fois (mais à peu près n'importe quel nombre supérieur à une ligne à la fois sera plus rapide qu'une ligne à la fois). Ceci est plus lent que la mise à jour, l'insertion ou la suppression du lot entier, mais plus rapide que les opérations ligne par ligne et peut être nécessaire dans un environnement de production avec de nombreux utilisateurs et peu de temps d'arrêt disponibles lorsque les utilisateurs n'essaient pas de voir et de mettre à jour d'autres enregistrements dans la même table. La taille du lot dépend grandement de la structure de la base de données et de ce qui se passe exactement (les tables avec des déclencheurs et beaucoup de contraintes sont plus lentes, tout comme les tables avec beaucoup de champs et nécessitent donc des lots plus petits).

0
HLGEM