PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да маркирате определен брой редове в таблицата при едновременен достъп

В свързания отговор имате предвид:

  • Актуализиране на Postgres... ОГРАНИЧЕНИЕ 1

Целта е да се заключи един ред по ред. Това работи добре със или без съветни заключвания, защото няма няма шанс за блокиране - стига да не се опитвате да заключите повече редове в една и съща транзакция.

Вашият пример е различен по това, че искате да заключите 3000 реда наведнъж . Имаи потенциал за блокиране, освен ако всички едновременни операции на запис заключват редове в същия последователен ред. По документация:

Най-добрата защита срещу блокиране обикновено е да ги избягвате, като сте сигурни, че всички приложения, използващи база данни, придобиват заключвания върху множество обекти в последователен ред.

Приложете това с ORDER BY във вашата подзаявка.

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;

Това е безопасно и надеждно, стига всички транзакциите придобиват заключвания в същия ред и не се очакват едновременни актуализации на колоните за поръчка. (Прочетете жълтото поле „ВНИМАНИЕ“ в края на тази глава в ръководството.) Така че това трябва да е безопасно във вашия случай, тъй като няма да актуализирате id колона.

Ефективно само един клиент в даден момент може да манипулира редове по този начин. Едновременните транзакции ще се опитат да заключат същите (заключени) редове и да изчакат първата транзакция да завърши.

Съветни ключалки са полезни, ако имате много или много продължителни едновременни транзакции (изглежда, че нямате). Само с няколко, като цяло ще бъде по-евтино просто да използвате горната заявка и да накарате едновременните транзакции да чакат своя ред.

Всичко в едно АКТУАЛИЗИРАНЕ

Изглежда, че едновременният достъп не е проблем сам по себе си във вашата настройка. Паралелността е проблем, създаден от текущото ви решение.

Вместо това го направете всичко с една UPDATE . Задайте партиди от n номера (3000 в примера) за всеки UUID и актуализирайте всички наведнъж. Би трябвало да е най-бързо.

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;

Основни точки

  • Целочисленото деление се съкращава. Получавате 1 за първите 3000 реда, 2 за следващите 3000 реда. и др.

  • Избирам редове произволно, можете да приложите ORDER BY в прозореца за row_number() за присвояване на определени редове.

  • Ако нямате таблица с UUID за изпращане (uuid_tbl ), използвайте VALUES израз, който да им осигури. Пример.

  • Получавате партиди от 3000 реда. Последната партида ще бъде под 3000, ако не намерите кратно на 3000 за присвояване.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SELECT повдига изключение във функцията PL/pgSQL

  2. INSERT IN... FROM SELECT ... ВРЪЩАНЕ на идентификационните съпоставяния

  3. Анотацията на Spring Boot Query с nativeQuery не работи в Postgresql

  4. Как да свържете приложение на C# Windows mobile 6.5 към база данни на Postgres?

  5. Надграждане на колона varchar до тип enum в postgresql