복붙노트

[SQL] 어떻게 동시 액세스에 테이블의 행의 특정 NR를 표시합니다

SQL

어떻게 동시 액세스에 테이블의 행의 특정 NR를 표시합니다

우리의 응용 프로그램은 테이블이라고 cargo_items 있습니다. 그것은 나중에 이러한 항목을 처리하는 큐의 일종으로 볼 수있다. 처음에 3000 개 항목을 가져다가 그들에게 잇달아 처리 한 일이 있었다. 나중에, 누군가가 같은 작업의 3 개 다른 인스턴스를 시작하기로 결정했다. 무슨 일이 것은 매우 명백하다, 많은 항목을 두 번 처리되었습니다.

내 작업은 동시에 여러 인스턴스가 실행중인 경우 제대로 작동 이러한 프로세스를 만드는 것입니다. 내가 지금 갈거야 솔루션은 작업 ID와 데이터베이스에 3000 개 항목을 표시하고 나중에이 모든 엔티티를 가져 그들을 다른 프로세스에서 분리 처리하는 것입니다.

이 행 신고에 대한 나의 현재의 접근 방식은 다음과 같다 :

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 
   LIMIT  3000
   FOR UPDATE
   ) sub
WHERE  item.id = sub.id;

기본적으로이 방법은 업데이트에 대한 3000 개 행을 잠급니다. 나는 확실히 그것이 비록 좋은 방법 아닌 경우입니다.

다른 스레드에 나는이 시나리오에 대한 자문 잠금을 사용하는 방법에 대해 읽어보십시오.

너희들은 무엇 현재의 접근 방식에 대해 생각하는 대신 자문 잠금을 사용합니까?

제안한 것처럼,이 같은 UPDATE 문을 적용 것입니다 :

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;

힌트에 대한 들으 어윈과 Tometzky. 그럼에도 불구하고 나는이 문제를 해결하기 위해 노력하고 방법이 좋은 경우 궁금해? 당신이 생각하는 것이 다른 접근 방법이 있습니까?

해결법

  1. ==============================

    1.당신이 언급하는 관련 대답 :

    당신이 언급하는 관련 대답 :

    목적은 한 번에 하나 개의 행을 잠그는 것입니다. 교착 상태에 대한 기회가 없기 때문에, 또는 자문 잠금없이 잘 작동합니다 - 당신이 동일한 트랜잭션에서 더 많은 행을 잠금을 시도하지 않는 길이로한다.

    귀하의 예는 한 번에 3000 개 행을 잠 그려는 점에서 다르다. 잠재력은 모든 동시 쓰기 작업이 일관된 순서로 행을 잠글 경우를 제외하고, 교착있다. 문서 별 :

    귀하의 하위 쿼리에 의해 주문과 그 구현.

    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에서 모든 작업을 수행 할 수 있습니다. 각 UUID에 n 개의 번호의 할당 배치 (예 3000)과는 한 번에 모든 업데이트합니다. 빠른이어야한다.

    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;
    
  2. ==============================

    2.당신은이 방법 교착 상태를해야합니다. 당신은 단순히 하위 쿼리의 ID로 순서를 사용하여이를 방지 할 수있다.

    당신은이 방법 교착 상태를해야합니다. 당신은 단순히 하위 쿼리의 ID로 순서를 사용하여이를 방지 할 수있다.

    동시 쿼리는 항상 가장 낮은 무료 ID를 표시하는 첫번째 시도하고 첫 번째 클라이언트가 커밋 할 때까지 차단으로하지만,이 쿼리의 동시 실행을 방지 할 수 있습니다. 나는 당신이 두 번째 미만 일괄 말을 처리 할 경우이 문제라고 생각하지 않습니다.

    당신은 자문 잠금이 필요하지 않습니다. 당신이 할 수있는 경우를 피하십시오.

  3. ==============================

    3.당신은 무엇이 필요 자문 잠금입니다.

    당신은 무엇이 필요 자문 잠금입니다.

       SELECT id
       FROM   cargo_item
       WHERE  pg_try_advisory_lock(id)
       LIMIT  3000
       FOR UPDATE
    

    동일한 pg_try_advisory_lock (ID) 기능이 어디에서 사용되는 경우, 행과 다른 프로세스에 권고 로크를 배치 할 것이 행을 볼 것이다. pg_advisory_unlock를 사용하여 행 잠금을 해제하는 것을 잊지 마십시오

  4. from https://stackoverflow.com/questions/27446515/how-to-mark-certain-nr-of-rows-in-table-on-concurrent-access by cc-by-sa and MIT license