하위 쿼리가 있는 pg_hint_plan
9081 단어 sqljoinpostgrespghintplan
예시:
drop table demo2, demo1;
create table demo1 ( id bigint primary key, a int, b int, d int);
create table demo2 ( id bigint primary key, a int, b int, d int);
insert into demo1 select generate_series(1,1000), 0, 0, 0 ;
vacuum analyze demo1;
vacuum analyze demo2;
insert into demo1 select generate_series(100000,200000), 0, 0, 0 ;
이제 테이블
demo1
에서 1000개의 행을 가져와 demo2
로 이동하는 다음 쿼리가 있습니다.explain (costs off, analyze)
WITH del AS(
DELETE FROM demo1 a
WHERE a.id in (SELECT id from demo1 my_batch limit 1000)
RETURNING *
) INSERT INTO demo2
SELECT id, a, b c
FROM del;
실행 계획은 다음과 같습니다.
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Insert on demo2 (actual time=18.627..18.635 rows=0 loops=1)
CTE del
-> Delete on demo1 a (actual time=0.415..17.051 rows=1000 loops=1)
-> Hash Semi Join (actual time=0.399..16.534 rows=1000 loops=1)
Hash Cond: (a.id = "ANY_subquery".id)
-> Seq Scan on demo1 a (actual time=0.006..10.032 rows=101001 loops=1)
-> Hash (actual time=0.355..0.360 rows=1000 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 79kB
-> Subquery Scan on "ANY_subquery" (actual time=0.006..0.256 rows=1000 loops=1)
-> Limit (actual time=0.003..0.131 rows=1000 loops=1)
-> Seq Scan on demo1 my_batch (actual time=0.002..0.089 rows=1000 loops=1)
-> CTE Scan on del (actual time=0.417..17.282 rows=1000 loops=1)
Planning Time: 0.247 ms
Execution Time: 18.702 ms
(14 rows)
postgres=#
이것은
demo1
가 해시 조인을 위한 프로브 테이블로 먼저 전체 스캔되기 때문에 그다지 효율적이지 않습니다. 기본적으로 PostgreSQL은 삭제하려는 1000개id
를 해시했지만 전체 테이블을 읽어서 찾습니다. 통계가 정확하지 않다고 생각할 수 있습니다. ANALYZE를 실행해 보십시오. 좋아, 하지만 내 목표는 많은 행을 삭제하는 것입니다(1000개 단위로). 전과 후를 분석하고 싶지 않습니다. 이것은 pg_hint_plan
가 도움이 되는 곳입니다. 내 쿼리(LIMIT 1000 포함) 설계에 따라 예측 가능한 성능(테이블 크기가 아닌 처리된 행 수에 따른 시간)을 얻기 위해 해당 행에서 중첩 루프가 필요합니다.조인이 삭제할 테이블인
demo1 a
와 1000demo1 my_batch
인 id
사이에 있다고 생각할 수 있지만 /*+ Leading( (my_batch a) ) NestLoop(my_batch a) */
와 같은 힌트를 얻으려고 하면 성공하지 못할 것입니다.실행 계획을 보십시오. 해시 조인은
Seq Scan on demo1 a
및 Subquery Scan on "ANY_subquery"
두 스캔 사이에 있습니다. 이것은 조인 순서, 방향 및 방법에 사용해야 하는 별칭을 제공합니다: a
및 "ANY_subquery"
중첩 루프를 강제로 실행하려는 경우 힌트
NestLoop("ANY_subquery" a)
를 추가할 수 있지만 이는 두 테이블 간의 조인이 중첩 루프 조인이어야 한다는 의미일 뿐입니다. 이 힌트에서 별칭의 순서는 중요하지 않습니다. 조인 쌍이 있는 Leading hind가 필요합니다: Leading( ("ANY_subquery" a) )
explain (costs off, analyze)
/*+ Leading( ("ANY_subquery" a) ) NestLoop("ANY_subquery" a) */
WITH del AS(
DELETE FROM demo1 a
WHERE a.id in (SELECT id from demo1 my_batch limit 1000)
RETURNING *
) INSERT INTO demo2
SELECT id, a, b c
FROM del;
이것이 내가 원하는 계획입니다.
QUERY PLAN
---------------------------------------------------------------------------------------------------------------
Insert on demo2 (actual time=4.267..4.268 rows=0 loops=1)
CTE del
-> Delete on demo1 a (actual time=0.521..2.219 rows=1000 loops=1)
-> Nested Loop (actual time=0.508..1.701 rows=1000 loops=1)
-> HashAggregate (actual time=0.492..0.641 rows=1000 loops=1)
Group Key: "ANY_subquery".id
Batches: 1 Memory Usage: 193kB
-> Subquery Scan on "ANY_subquery" (actual time=0.069..0.305 rows=1000 loops=1)
-> Limit (actual time=0.065..0.177 rows=1000 loops=1)
-> Seq Scan on demo1 my_batch (actual time=0.064..0.134 rows=1000 loops=1)
-> Index Scan using demo1_pkey on demo1 a (actual time=0.001..0.001 rows=1 loops=1000)
Index Cond: (id = "ANY_subquery".id)
-> CTE Scan on del (actual time=0.523..2.526 rows=1000 loops=1)
Planning Time: 0.231 ms
Execution Time: 4.362 ms
(15 rows)
4.362 ms
vs. 18.702 ms
가 빨라서 행복하다고 생각하세요? 전혀. 나는 그 밀리 초에 대해 신경 쓰지 않습니다. 이 계획을 선호하는 이유는 확장성입니다. 여기서는 소스 테이블의 크기에 따라 달라지는 작업이 없습니다. 내 힌트 덕분에 오래된 통계로 인해 O(N) 없음으로 전환할 위험이 없는 O(1) 복잡성을 보장합니다.이 예제는 PostgreSQL(
pg_hint_plan
확장 포함) 또는 호환 가능(pg_hint_plan
이 기본적으로 설치된 YugabyteDB와 같은)에서 실행됩니다.
Reference
이 문제에 관하여(하위 쿼리가 있는 pg_hint_plan), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/aws-heroes/pghintplan-with-subqueries-47nm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)