Postgres에서 동시 업데이트 최적화


9

다음과 같이 동시 Postgres 쿼리를 실행하고 있습니다.

UPDATE foo SET bar = bar + 1 WHERE baz = 1234

각 쿼리는 고정 K 행 수에 영향을 미치며 행이 업데이트되는 순서를 적용하는 방법을 찾을 수 없으므로 교착 상태가 발생합니다. 현재 수동으로 명령을 시행하여 문제를 해결하지만 이는 평소보다 더 많은 쿼리를 실행해야하며 검색 복잡성을 O (log N + K)에서 O (K log N)으로 높이는 것을 의미합니다.

교착 상태에 취약하게하지 않고 성능을 향상시킬 수있는 방법이 있습니까? Postgres가 행을 스캔 한 것과 동일한 순서로 행을 업데이트하는 (baz)경우 (baz, id)인덱스를 인덱스로 바꾸면 작동 할 수 있다고 생각합니다. 이 방법은 추구 할 가치가 있습니까?


CREATE TABLE코드 를 추가하는 것이 좋습니다 .
ypercubeᵀᴹ

답변:


15

더 없다 ORDER BYSQL UPDATE명령. Postgres는 임의의 순서로 행을 업데이트합니다.

절대 확실성을 갖는 교착 상태를 피하기 위해 직렬화 가능한 트랜잭션 격리 에서 명령문을 실행할 수 있습니다 . 그러나 더 비싸므로 직렬화 실패에 대한 명령을 반복하도록 준비해야합니다.

가장 좋은 방법 은 트랜잭션 SELECT ... ORDER BY ... FOR UPDATE의 하위 쿼리 또는 독립 실행 형 ( SELECT기본적으로 "읽기 커밋 된"격리 수준) 으로 명시 적으로 잠그는 것입니다 . pgsql-general에서 Tom Lane 인용 :

FOR UPDATE 잠금은 항상 SELECT 파이프 라인의 마지막 단계입니다.

이것은 일을해야합니다 :

BEGIN;

SELECT 1
FROM   foo 
WHERE  baz = 1234
ORDER  BY bar
FOR    UPDATE;

UPDATE foo
SET    bar = bar + 1
WHERE  baz = 1234;

COMMIT;

여러 열 인덱스 (baz, bar)가 성능에 완벽 할 수 있습니다. 그러나 bar분명히 많이 업데이트되었으므로 단일 열 인덱스 (baz)가 더 좋을 수 있습니다. 몇 가지 요인에 따라 다릅니다. 한 줄에 몇 개의 행이 baz있습니까? 인가 HOT 업데이트 멀티 컬럼 인덱스없이 가능한가? ...

경우 baz 동시에 업데이트되고있을 법 여전히 존재 코너의 경우 충돌 가능성 (문서 당)은 :

그것은 가능하다 SELECT상기 실행 명령 READ COMMITTED 트랜잭션 격리 수준 및 사용 ORDER BY과 고장의 행을 반환하는 잠금 절. ...

당신이 관련된 고유 제한 조건이 있어야 경우에도 bar, 고려 DEFERRABLE제약 조건을 같은 명령 내에서 고유 위반을 피하기 위해. 관련 답변 :


1
id대신 주문 하거나 다른 고유 한 열을 주문하는 bar경우 코너 케이스 나 성능 저하가 없어야합니까?
Alexei Averchenko 12

@AlexeiAverchenko : 예, 절대 업데이트되지 않는 고유 한 열은이 열에 적합합니다.이 열은 두 번째 위치에 포함됩니다.
Erwin Brandstetter 2018 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.