sql >> Database >  >> RDS >> PostgreSQL

Hoe een bepaald aantal rijen in de tabel te markeren bij gelijktijdige toegang?

In het gerelateerde antwoord waarnaar u verwijst:

  • Postgres-UPDATE ... LIMIET 1

Het doel is om één . te vergrendelen rij tegelijk. Dit werkt prima met of zonder adviesvergrendelingen, omdat er geen kans is op een impasse - zolang u niet meer rijen in dezelfde transactie probeert te vergrendelen.

Uw voorbeeld is anders omdat u 3000 rijen tegelijk . wilt vergrendelen . Er is is potentieel voor deadlock, behalve als alle gelijktijdige schrijfbewerkingen rijen in dezelfde consistente volgorde vergrendelen. Per documentatie:

De beste verdediging tegen deadlocks is over het algemeen om ze te vermijden door er zeker van te zijn dat alle toepassingen die een database gebruiken vergrendelingen op meerdere objecten in een consistente volgorde verwerven.

Implementeer dat met een ORDER BY in uw subquery.

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;

Dit is veilig en betrouwbaar, zolang alle transacties verkrijgen sloten in dezelfde volgorde en gelijktijdige updates van de bestelkolommen zijn niet te verwachten. (Lees het gele vak "LET OP" aan het einde van dit hoofdstuk in de handleiding.) Dit zou in uw geval dus veilig moeten zijn, aangezien u de id niet gaat bijwerken. kolom.

In feite kan slechts één client tegelijk rijen op deze manier manipuleren. Gelijktijdige transacties zouden proberen dezelfde (vergrendelde) rijen te vergrendelen en te wachten tot de eerste transactie is voltooid.

Adviessloten zijn handig als u veel of zeer langlopende gelijktijdige transacties heeft (het lijkt erop dat u dat niet doet). Met slechts een paar is het over het algemeen goedkoper om alleen bovenstaande zoekopdracht te gebruiken en gelijktijdige transacties op hun beurt te laten wachten.

Alles in één UPDATE

Het lijkt erop dat gelijktijdige toegang niet per se een probleem is in uw setup. Gelijktijdigheid is een probleem dat wordt veroorzaakt door uw huidige oplossing.

Doe het in plaats daarvan allemaal in één UPDATE . Wijs batches van n . toe nummers (3000 in het voorbeeld) toe aan elke UUID en werk ze allemaal tegelijk bij. Zou de snelste moeten zijn.

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;

Belangrijkste punten

  • Deling van gehele getallen wordt afgekapt. Je krijgt 1 voor de eerste 3000 rijen, 2 voor de volgende 3000 rijen. enz.

  • Ik kies willekeurig rijen, je zou ORDER BY kunnen toepassen in het venster voor row_number() om bepaalde rijen toe te wijzen.

  • Als u geen tabel met UUID's hebt om te verzenden (uuid_tbl ), gebruik een VALUES uitdrukking om ze te leveren. Voorbeeld.

  • U krijgt batches van 3000 rijen. De laatste batch heeft minder dan 3000 als je geen veelvoud van 3000 kunt vinden om toe te wijzen.



  1. Oracle (+) operator

  2. ORA-00257:archieffout. Sluit alleen intern aan, totdat het wordt vrijgemaakt.

  3. Ontdek 10 minder bekende mogelijkheden van SQL Diagnostic Manager

  4. Ignition verbinden met Microsoft Access