sql >> Databasteknik >  >> RDS >> PostgreSQL

Postgres UPPDATERING med BESTÄLLNING AV, hur gör man?

Så vitt jag vet finns det inget sätt att åstadkomma detta direkt genom UPDATE påstående; det enda sättet att garantera låsordning är att explicit skaffa lås med en SELECT ... ORDER BY ID FOR UPDATE , t.ex.:

UPDATE Balances
SET Balance = 0
WHERE ID IN (
  SELECT ID FROM Balances
  WHERE ID IN (SELECT ID FROM some_function())
  ORDER BY ID
  FOR UPDATE
)

Detta har nackdelen med att upprepa ID indexsökning på Balances tabell. I ditt enkla exempel kan du undvika denna overhead genom att hämta den fysiska radadressen (representerad av ctid systemkolumn ) under låsningsfrågan och använda den för att driva UPDATE :

UPDATE Balances
SET Balance = 0
WHERE ctid = ANY(ARRAY(
  SELECT ctid FROM Balances
  WHERE ID IN (SELECT ID FROM some_function())
  ORDER BY ID
  FOR UPDATE
))

(Var försiktig när du använder ctid s, eftersom värdena är övergående. Vi är säkra här, eftersom låsen blockerar alla ändringar.)

Tyvärr kommer planeraren bara använda ctid i en snäv uppsättning fall (du kan se om det fungerar genom att leta efter en "Tid Scan"-nod i EXPLAIN produktion). För att hantera mer komplicerade frågor inom en enda UPDATE uttalande, t.ex. om ditt nya saldo returnerades av some_function() bredvid ID:t måste du gå tillbaka till den ID-baserade uppslagningen:

UPDATE Balances
SET Balance = Locks.NewBalance
FROM (
  SELECT Balances.ID, some_function.NewBalance
  FROM Balances
  JOIN some_function() ON some_function.ID = Balances.ID
  ORDER BY Balances.ID
  FOR UPDATE
) Locks
WHERE Balances.ID = Locks.ID

Om prestandaoverhead är ett problem, måste du använda en markör, som skulle se ut ungefär så här:

DO $$
DECLARE
  c CURSOR FOR
    SELECT Balances.ID, some_function.NewBalance
    FROM Balances
    JOIN some_function() ON some_function.ID = Balances.ID
    ORDER BY Balances.ID
    FOR UPDATE;
BEGIN
  FOR row IN c LOOP
    UPDATE Balances
    SET Balance = row.NewBalance
    WHERE CURRENT OF c;
  END LOOP;
END
$$


  1. Fel 2002 Connection vägrade när PHP ansluter till MySQL som körs på MAMP

  2. Hur förhindrar man att SUB tolkar ett frågetecken som en platshållare?

  3. ASP.NET MVC + MySql-medlemsleverantör, användaren kan inte logga in

  4. Är MySQL Connector/JDBC tråd säker?