sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur man markerar ett visst antal rader i tabellen vid samtidig åtkomst

I det relaterade svaret syftar du på:

  • Postgres UPPDATERING ... GRÄNS 1

Målet är att låsa en rad åt gången. Detta fungerar bra med eller utan rådgivande lås, eftersom det ingen risk för ett dödläge - så länge du inte försöker låsa fler rader i samma transaktion.

Ditt exempel är annorlunda genom att du vill låsa 3000 rader åt gången . Det finns potential för dödläge, förutom om alla samtidiga skrivoperationer låser rader i samma konsekventa ordning. Per dokumentation:

Det bästa försvaret mot dödlägen är i allmänhet att undvika dem genom att vara säker på att alla applikationer som använder en databas får lås på flera objekt i en konsekvent ordning.

Implementera det med en ORDER BY i din underfråga.

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;

Detta är säkert och pålitligt, så länge som alla transaktioner får lås i samma ordning och samtidiga uppdateringar av beställningskolumnerna är inte att förvänta. (Läs den gula "VARNING"-rutan i slutet av det här kapitlet i manualen.) Så detta bör vara säkert i ditt fall, eftersom du inte kommer att uppdatera id kolumn.

I praktiken kan endast en klient åt gången manipulera rader på detta sätt. Samtidiga transaktioner skulle försöka låsa samma (låsta) rader och vänta på att den första transaktionen slutförs.

Rådgivningslås är användbara om du har många eller mycket långvariga samtidiga transaktioner (verkar inte göra det). Med bara ett fåtal blir det totalt sett billigare att bara använda ovanstående fråga och låta samtidigt transaktioner vänta på sin tur.

Allt i en UPPDATERING

Det verkar som om samtidig åtkomst inte är ett problem i sig i din installation. Samtidighet är ett problem som skapas av din nuvarande lösning.

Gör det istället allt i en enda UPDATE . Tilldela batcher av n nummer (3000 i exemplet) till varje UUID och uppdatera allt på en gång. Bör vara snabbast.

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;

Huvudpunkter

  • Heltalsdivision trunkeras. Du får 1 för de första 3000 raderna, 2 för de nästa 3000 raderna. etc.

  • Jag väljer rader godtyckligt, du kan använda ORDER BY i fönstret för row_number() för att tilldela vissa rader.

  • Om du inte har en tabell med UUID att skicka (uuid_tbl ), använd en VALUES uttryck för att tillhandahålla dem. Exempel.

  • Du får satser på 3000 rader. Den sista batchen kommer att sakna 3000 om du inte hittar en multipel av 3000 att tilldela.



  1. MySQL-utlösare vid Infoga/Uppdatera händelser

  2. Wordpress Fatalt fel:Oupptäckt fel:Anrop till odefinierad funktion mysql_connect() i /wp-includes/wp-db.php:1570

  3. NodeJS MySQL Dump

  4. Få det nya postens primärnyckel-ID från MySQL-infogningsfrågan?