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

Jak označit určitý počet řádků v tabulce při souběžném přístupu

V související odpovědi máte na mysli:

  • AKTUALIZACE Postgresu... LIMIT 1

Cílem je zamknout jeden řádek najednou. Funguje to dobře s nebo bez poradních zámků, protože neexistuje žádná šance na uváznutí - pokud se nepokusíte uzamknout více řádků ve stejné transakci.

Váš příklad se liší v tom, že chcete uzamknout 3000 řádků najednou . existuje potenciální uváznutí, kromě případů, kdy všechny souběžné operace zápisu zamykají řádky ve stejném konzistentním pořadí. Podle dokumentace:

Nejlepší obranou proti uváznutí je obecně se jim vyhnout tím, že si budete jisti, že všechny aplikace používající databázi získávají zámky na více objektech v konzistentním pořadí.

Implementujte to pomocí příkazu ORDER BY ve vašem dílčím dotazu.

UPDATE cargo_item item
SET job_id = 'SOME_UUID', job_ts = now()
FROM  ( 
   SELECT id
   FROM   cargo_item
   WHERE  state='NEW' AND job_id is null 
   ORDER  BY id
   LIMIT  3000
   FOR UPDATE
   ) sub
WHERE  item.id = sub.id;

To je bezpečné a spolehlivé, pokud vše transakce získávají zámky ve stejném pořadí a nelze očekávat souběžné aktualizace objednávkových sloupců. (Přečtěte si žluté pole „POZOR“ na konci této kapitoly v příručce.) Ve vašem případě by to tedy mělo být bezpečné, protože nebudete aktualizovat id sloupec.

Tímto způsobem může efektivně manipulovat s řádky pouze jeden klient současně. Souběžné transakce by se pokusily uzamknout stejné (uzamčené) řádky a čekaly by na dokončení první transakce.

Poradní zámky jsou užitečné, pokud máte mnoho nebo velmi dlouho probíhajících souběžných transakcí (zdá se, že ne). Jen s několika bude celkově levnější použít výše uvedený dotaz a nechat souběžné transakce čekat, až na ně přijde řada.

AKTUALIZACE VŠE v jednom

Zdá se, že souběžný přístup nepředstavuje problém jako takový ve vašem nastavení. Souběžnost je problém vytvořený vaším aktuálním řešením.

Místo toho to udělejte vše v jediném UPDATE . Přiřaďte dávky n čísla (v příkladu 3000) ke každému UUID a aktualizujte je všechny najednou. Mělo by to být nejrychlejší.

UPDATE cargo_item c
SET    job_id = u.uuid_col
     , job_ts = now()
FROM  (
   SELECT row_number() OVER () AS rn, uuid_col
   FROM   uuid_tbl WHERE  <some_criteria>  -- or see below
   ) u
JOIN (
   SELECT (row_number() OVER () / 3000) + 1 AS rn, item.id 
   FROM   cargo_item
   WHERE  state = 'NEW' AND job_id IS NULL
   FOR    UPDATE   -- just to be sure
   ) c2 USING (rn)
WHERE  c2.item_id = c.item_id;

Hlavní body

  • Celočíselné dělení se zkracuje. Získáte 1 pro prvních 3000 řádků, 2 pro dalších 3000 řádků. atd.

  • Řádky vybírám libovolně, můžete použít ORDER BY v okně pro row_number() přiřadit určité řádky.

  • Pokud nemáte tabulku UUID k odeslání (uuid_tbl ), použijte VALUES výraz, který jim dodá. Příklad.

  • Získáte dávky 3000 řádků. Pokud nenajdete násobek 3000 k přiřazení, bude poslední dávka kratší než 3000.



  1. Získejte hodnoty z prvního a posledního řádku na skupinu

  2. Analýza názvů tabulek a sloupců z SQL/HQL Java

  3. Tipy pro výkon XML

  4. 4 způsoby, jak nahradit NULL jinou hodnotou v MySQL