sql >> Databáze >  >> RDS >> PostgreSQL

Postgres UPDATE pomocí ORDER BY, jak na to?

Pokud vím, neexistuje způsob, jak toho dosáhnout přímo prostřednictvím UPDATE tvrzení; jediný způsob, jak zaručit pořadí zámků, je explicitně získat zámky pomocí SELECT ... ORDER BY ID FOR UPDATE , např.:

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
)

To má nevýhodu v opakování ID vyhledávání indexu na Balances stůl. Ve vašem jednoduchém příkladu se této režii můžete vyhnout načtením adresy fyzického řádku (reprezentované ctid systémový sloupec ) během zamykacího dotazu a pomocí toho řídit 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
))

(Při používání ctid buďte opatrní s, protože hodnoty jsou přechodné. Jsme zde v bezpečí, protože zámky zablokují jakékoli změny.)

Plánovač bohužel použije pouze ctid v úzké sadě případů (jestli to funguje, zjistíte tak, že v EXPLAIN najdete uzel „Tid Scan“ výstup). Pro zpracování složitějších dotazů v rámci jednoho UPDATE prohlášení, např. pokud byl váš nový zůstatek vrácen pomocí some_function() vedle ID se budete muset vrátit k vyhledávání založenému na ID:

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

Pokud je problém s režií výkonu, budete se muset uchýlit k použití kurzoru, který by vypadal asi takto:

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. Prohledejte všechny sloupce tabulky pomocí jediné podmínky where s jedním klíčovým slovem v mysql

  2. Jak porovnat dvě tabulky sloupec po sloupci v oracle

  3. MySQL:porovnání celočíselné hodnoty a pole řetězce s indexem

  4. Použití Oracle JDeveloper s databázovou službou MySQL na platformě Oracle Cloud, část 2