postgresql의 긴 업데이트
-
05-07-2019 - |
문제
저는 3개의 인덱스가 있는 2억 5천만 개의 행이 포함된 테이블에서 UPDATE를 실행했습니다.';이 업데이트는 3천만 개의 행을 포함하는 다른 테이블을 사용합니다.현재 약 36시간 동안 실행되고 있습니다.나는 그것이 완료되기까지 얼마나 가까웠는지 알아내는 방법인지 궁금합니다. 작업을 수행하는 데 백만 일이 걸릴 계획이라면 나는 그것을 죽일 것입니다.하지만 하루나 이틀만 더 필요하다면 실행하도록 하겠습니다.명령 쿼리는 다음과 같습니다.
UPDATE pagelinks SET pl_to = page_id
FROM page
WHERE
(pl_namespace, pl_title) = (page_namespace, page_title)
AND
page_is_redirect = 0
;
EXPLAIN은 여기서 문제가 아니며 업데이트하는 데 걸리는 시간을 어느 정도 정당화하기 위해 큰 테이블에 여러 인덱스가 있다는 점만 언급합니다.하지만 어쨌든 EXPLAIN은 다음과 같습니다.
Merge Join (cost=127710692.21..135714045.43 rows=452882848 width=57)
Merge Cond: (("outer".page_namespace = "inner".pl_namespace) AND ("outer"."?column4?" = "inner"."?column5?"))
-> Sort (cost=3193335.39..3219544.38 rows=10483593 width=41)
Sort Key: page.page_namespace, (page.page_title)::text
-> Seq Scan on page (cost=0.00..439678.01 rows=10483593 width=41)
Filter: (page_is_redirect = 0::numeric)
-> Sort (cost=124517356.82..125285665.74 rows=307323566 width=46)
Sort Key: pagelinks.pl_namespace, (pagelinks.pl_title)::text"
-> Seq Scan on pagelinks (cost=0.00..6169460.66 rows=307323566 width=46)
이제 다음 중 하나를 삭제하기 위해 병렬 쿼리 명령도 보냈습니다. 페이지링크' 인덱스;물론 업데이트가 완료되기를 기다리고 있습니다(하지만 어쨌든 시도해 보고 싶었습니다!).그러므로 나는 아무것도 선택할 수 없습니다 페이지링크 데이터 손상을 두려워합니다(DROP INDEX 포스트마스터 프로세스를 종료하는 것이 안전하다고 생각하지 않는 한?).
따라서 데드 튜플의 양을 추적하는 테이블인지 궁금합니다. 업데이트가 작업을 완료하는 데 얼마나 빠르거나 얼마나 멀리 걸리는지 아는 것이 좋을 것입니다.
thx (postgresql은 내가 생각했던 것만 큼 지능적이지 않습니다.휴리스틱이 필요함)
해결책
"PostgreSQL 문서를 읽었습니까?"설명 사용", 당신이 보여주는 출력을 해석하기 위해?
나는 일반 PostgreSQL 사용자가 아니지만 그 문서를 읽은 다음 EXPLAIN
당신이 보여주는 출력. 당신의 UPDATE
쿼리는 인덱스를 사용하지 않는 것 같습니다. page
그리고 pagelinks
. 이 종류는 임시 디스크 파일이 필요할 정도로 의심 할 여지가 없습니다. temp_tablespace
.
그런 다음 추정 데이터베이스 페이지가 읽는 것을 볼 수 있습니다. 그것의 최상위 EXPLAIN
출력이 말합니다 (cost=127710692.21..135714045.43)
. 여기의 장치는 디스크 I/O 액세스에 있습니다. 그래서이 작업을 수행하기 위해 1 억 3 천 5 백만 번 이상 디스크에 액세스 할 것입니다. UPDATE
.
5ms를 찾는 시간이있는 10,000rpm 디스크조차도 최적의 조건에서 초당 200 I/O 작업을 최대한 활용할 수 있습니다. 이것은 당신의 의미입니다 UPDATE
해당 기간 동안 포화 디스크 I/O를 유지할 수 있더라도 188 시간 (7.8 일)의 디스크 I/O가 소요됩니다 (즉, 휴식없이 연속 읽기/쓰기). 이것은 불가능하며, 특히 실제 처리량이 적어도 몇 배나 꺼질 것으로 예상됩니다. 특히 그 동안이 서버를 다른 모든 작업에 사용하고 있었기 때문입니다. 그래서 나는 당신이 당신의 길의 일부일 뿐인 것 같아요 UPDATE
.
그것이 나라면, 나는 첫날이 쿼리를 죽이고 또 다른 방법을 찾았을 것입니다. UPDATE
이로 인해 인덱스를 더 잘 활용했으며 디스크 정렬이 필요하지 않았습니다. 당신은 아마 단일 SQL 문으로 그것을 할 수 없을 것입니다.
당신의 DROP INDEX
, 나는 그것이 단순히 막히고, 테이블에 대한 독점적 인 액세스를 기다리는 것을 기다리고 있다고 생각합니다. 그리고이 상태에있는 동안 아마 당신은 그것을 죽일 수 있다고 생각합니다.
다른 팁
이것은 매우 오래되었지만 업데이트를 모니터링할 수 있는 방법을 원한다면...시퀀스는 전역적으로 영향을 받으므로 다음을 수행하여 다른 세션에서 이 업데이트를 모니터링하기 위한 시퀀스를 만들 수 있습니다.
create sequence yourprogress;
UPDATE pagelinks SET pl_to = page_id
FROM page
WHERE
(pl_namespace, pl_title) = (page_namespace, page_title)
AND
page_is_redirect = 0 AND NEXTVAL('yourprogress')!=0;
그런 다음 다른 세션에서 다음을 수행합니다(시퀀스는 전역적으로 영향을 받으므로 트랜잭션에 대해 걱정하지 마십시오).
select last_value from yourprogress;
그러면 영향을 받는 회선 수가 표시되므로 시간이 얼마나 걸릴지 추정할 수 있습니다.
마지막에 시퀀스를 다시 시작하여 또 다른 시도를 해보세요.
alter sequence yourprogress restart with 1;
아니면 그냥 버리세요:
drop sequence yourprogress;
인덱스가 필요하거나 Bill이 지적했듯이 모든 테이블에서 순차적 스캔을해야합니다.
CREATE INDEX page_ns_title_idx on page(page_namespace, page_title);
CREATE INDEX pl_ns_title_idx on pagelink(pl_namespace, pl_title);
CREATE INDEX page_redir_idx on page(page_is_redirect);