2017-03-16 1 views
3

J'ai une table qui contient environ 50M lignes. Je veux exécuter une simple requête UPDATE:Postgres - Pas de mise à jour, a-t-il des effets secondaires?

UPDATE the_table SET flag = true; 

Pour 99% de ces lignes, le drapeau est déjà défini sur true. Donc, seulement 1% des lignes doivent être changées.

Ma question est: est-ce que Postgres est assez intelligent pour le savoir? Ou Postgres changera quand même ces 99% de lignes, ce qui se traduira par des processus typiques tels que WAL, auto-vacuum, réindexation, synchronisation avec les esclaves, ... pour toute la table, au lieu de seulement pour ces lignes de 1%. En d'autres termes, la requête suivante est-elle une approche plus sûre?

UPDATE the_table SET flag = true WHERE flag = false; 
+0

il va mettre à jour autant de lignes que le dire. Dans votre cas sans 'where' il va mettre à jour toutes les lignes, alors bien sûr aller pour la deuxième déclaration –

+0

Obligatory use where clause, sinon toutes les lignes seront affectées. – klin

Répondre

2

Postgres sera pas fait de distinction entre le cas où flag = true ou flag = false (ou drapeau est nulle, pour cette matière) lors de l'exécution de la mise à jour. Cependant, les résultats des deux déclarations ne sont pas complètement équivalents; ou, au moins, ils ne sont pas en général.

Il y a deux principaux effets secondaires:

  1. La première requête (pas where) va scanner et traiter toutes les lignes de la table. Dans le second cas, et avec des indices appropriés, il se peut que l'on ne fasse que quelques lignes. Le résultat final en termes de «ce qui est sur la table» (sauf les effets des déclencheurs) sera le même. Le temps nécessaire pour atteindre ce résultat final pourrait être sensiblement différent.

  2. Si la table (ou vue) a un trigger que les incendies « ON UPDATE » et « pour chaque ligne » (voir CREATE TRIGGER), la fonction de déclenchement sera appelée pour chaque ligne sur la table avec votre première requête, et uniquement pour les lignes WHEREoù la condition est vraie sur la seconde. Encore deux différences: (1) le temps et (2) l'action du déclencheur. Si le déclencheur, par exemple, met à jour une colonne "lastmod", il le mettra à jour pour chaque ligne dans le premier cas [ce qui n'est probablement pas ce que vous voulez].

... et un possible troisième:

  1. Dans un scénario suffisamment concurrent: la première requête bloque toutes les lignes de la table; ou l'instruction peut être bloquée de la mise à jour de certaines lignes car une autre transaction leur est simultanément. Donc, soit de longues périodes d'attente ou de blocage. Plus le nombre de lignes mises à jour, plus la probabilité d'avoir des effets sur contention ... (ou de blocage, etc.)

La façon la plus habituelle de mise à jour utilise une requête avec une clause WHERE.Certains cas très spéciaux pourraient recommander le premier (par exemple, vous voulez réellement une colonne "lastmod" mise à jour, même si le reste des valeurs de la ligne ne l'étaient pas). "Par défaut" pour la requête avec WHERE. Certaines bases de données (par exemple: MySQL et safe update) peuvent même ne pas vous permettre d'exécuter une mise à jour (ou supprimer) sans une clause WHERE.

4

Non, Postgres ne vérifie pas si vous mettez à jour à la même valeur. De temps en temps, cela est discuté sur la liste de diffusion, mais le consensus est que le chèque est trop cher et il est inutile de faire payer tous les utilisateurs pour quelque chose que seulement quelques utilisateurs (généralement des utilisateurs de couches d'obfuscation mauvaises - aka "ORM") besoin.

La deuxième solution est la meilleure et la plus sûre pour effectuer la mise à jour.

+0

Calques d'obscurcissement - alias "ORM";) – klin

+1

@klin: ORM ne signifie-t-il pas "Modèle Relié Obfusqué"? :) –

+2

Je le pense, surtout quand je vois des questions comme * Comment puis-je écrire cette requête dans mon ORM? * – klin