PostgreSQL이 정확히 알려주는 것은 무엇입니까?


116

MySQL의 Explain 출력은 매우 간단합니다. PostgreSQL은 좀 더 복잡합니다. 나는 그것을 설명하는 좋은 자료를 찾을 수 없었다.

설명이 정확히 무엇을 말하고 있는지 설명하거나 최소한 좋은 리소스의 방향을 알려줄 수 있습니까?

답변:


50

Explaining_EXPLAIN.pdf 도 도움이 될 수 있습니다.


64
사람들이 슬라이드 데크가 좋은 기술 문서가된다고 생각하는 이유가 궁금합니다. 강연 동영상이 도움이 될 수 있지만 해당 슬라이드 데크의 정보 밀도는 거의 0에 가깝습니다. 처음 6 개의 슬라이드 (전체의 1/5)에는 정확히 1 개의 기술 콘텐츠 문장이 있습니다. "• EXPLAIN은 SELECT (즉, UPDATE, DELETE 및 INSERT)뿐만 아니라 모든 DML에서 작동합니다." 내 가장 큰 오해는 "시작"시간이 의미하는 바이며이 30 개 슬라이드에서는 설명하지 않습니다.
Mark E. Haase

80

내가 항상 헷갈리는 부분은 시작 비용과 총 비용입니다. 나는 그것을 잊을 때마다 이것을 구글로 여기고 여기로 돌아와서 차이점을 설명하지 못합니다. 이것이 제가이 답변을 쓰는 ​​이유입니다. 이 내가에서 수집 한 것입니다 포스트 그레스 EXPLAIN문서 , 내가 그것을 이해 설명했다.

다음은 포럼을 관리하는 애플리케이션의 예입니다.

EXPLAIN SELECT * FROM post LIMIT 50;

Limit  (cost=0.00..3.39 rows=50 width=422)
  ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

다음은 PgAdmin의 그래픽 설명입니다.

첫 번째 쿼리에 대한 그래픽 설명

(PgAdmin을 사용하는 경우 구성 요소를 마우스로 가리키면 비용 세부 정보를 읽을 수 있습니다.)

비용은 튜플로 표시됩니다. 예를 들어 LIMITis cost=0.00..3.39비용과 순차적 스캔 비용 postcost=0.00..15629.12. 튜플의 첫 번째 숫자는 시작 비용 이고 두 번째 숫자는 총 비용 입니다. 내가 사용 EXPLAIN하고 사용 하지 않았기 때문에 EXPLAIN ANALYZE이러한 비용은 실제 측정이 아닌 추정치입니다.

  • 시작 비용 은 까다로운 개념입니다. 구성 요소 가 시작 되기 전의 시간을 나타내는 것이 아닙니다 . 구성 요소가 실행 (데이터 읽기)을 시작하고 구성 요소가 첫 번째 행을 출력 할 때까지의 시간을 나타냅니다 .
  • 총 비용 은 데이터 읽기 시작 시점부터 출력 쓰기 완료 시점까지 구성 요소의 전체 실행 시간입니다.

문제로 각 "상위"노드의 비용에는 하위 노드의 비용이 포함됩니다. 텍스트 표현에서 트리는 들여 쓰기로 표시됩니다. 예를 들어 LIMIT부모 노드이고 Seq Scan그 자식입니다. PgAdmin 표현에서 화살표는 자식에서 부모 (데이터 흐름의 방향)를 가리 킵니다. 그래프 이론에 익숙하다면 직관적이지 않을 수 있습니다.

문서에 따르면 비용에는 모든 하위 노드가 포함되지만 상위 3.39의 총 비용은 하위의 총 비용보다 훨씬 적습니다 15629.12. 같은 구성 요소 LIMIT는 전체 입력을 처리 할 필요가 없기 때문에 총 비용은 포함 되지 않습니다. Postgres 설명서EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;예제를 참조하십시오 .EXPLAIN

위의 예에서 시작 시간은 두 구성 요소 모두에 대해 0입니다. 두 구성 요소 모두 행 쓰기를 시작하기 전에 처리를 수행 할 필요가 없기 때문입니다. 순차 스캔은 테이블의 첫 번째 행을 읽고이를 내 보냅니다. 는 LIMIT자사의 첫 번째 행을 읽고 다음을 방출한다.

구성 요소가 행 출력을 시작하기 전에 많은 처리를 수행해야하는시기는 언제입니까? 가능한 많은 이유가 있지만 한 가지 명확한 예를 살펴 보겠습니다. 다음은 이전과 동일한 쿼리이지만 이제 ORDER BY절을 포함합니다 .

EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;

Limit  (cost=23283.24..23283.37 rows=50 width=422)
  ->  Sort  (cost=23283.24..23859.27 rows=230412 width=422)
        Sort Key: body
        ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

그리고 그래픽 :

두 번째 쿼리에 대한 그래픽 설명

다시 한 번, 순차 스캔 post에는 시작 비용이 없습니다. 즉, 행 출력을 즉시 시작합니다. 그러나 정렬은 단일 행을 출력하기 전에 전체 테이블23283.24정렬해야 하므로 시작 비용이 많이 듭니다 . 정렬의 총 비용은 23859.27시작 비용보다 약간 높으며, 전체 데이터 세트가 정렬되면 정렬 된 데이터를 매우 빠르게 내보낼 수 있다는 사실을 반영합니다.

공지의 시작 시간은 LIMIT 23283.24정렬의 시작 시간을 정확히 동일합니다. 이는 LIMIT자체적으로 시작 시간이 길기 때문이 아닙니다 . 실제로 자체적으로 시작 시간은 0이지만 EXPLAIN각 부모의 모든 자식 비용을 롤업하므로 LIMIT시작 시간에는 자식의 총 시작 시간이 포함됩니다.

이러한 비용 롤업은 각 개별 구성 요소의 실행 비용을 이해하기 어렵게 만들 수 있습니다. 예를 들어, 우리 LIMIT는 시작 시간이 0이지만 언뜻보기에는 분명하지 않습니다. 이러한 이유로, 여러 가지 다른 사람들과 연결 explain.depesz.com , 이해하는 데 도움이 휴 버트 Lubaczewski (일명 depesz)에 의해 생성 된 도구 EXPLAIN무엇보다도 - - 부모의 비용에서 아이의 비용을 빼서을. 그는 자신의 도구에 대한 짧은 블로그 게시물 에서 몇 가지 다른 복잡성을 언급합니다 .


4
감사합니다. 또한 출력 (imo)을 더 잘 표시하는 Explain Visualizer를 추가하고 싶습니다. tatiyants.com/pev
Jonathan Porter

좋은 대답입니다. 그리고 시작 비용에 반환 된 첫 번째 행까지의 시간이 포함 된다는 귀하의 의견 은 Sort의 시작 비용이 15629.12가 아닌 이유를 이해하는 데 도움이되었습니다.
Joel Wigton

43

가장 들여 쓴 것부터 가장 적게 들여 쓴 것까지 실행되며 계획의 맨 아래에서 맨 위로 이동한다고 생각합니다. (두 개의 들여 쓰기 된 섹션이있는 경우 페이지 아래쪽에있는 섹션이 먼저 실행되고 다른 섹션을 만나면 해당 섹션을 결합하는 규칙이 실행됩니다.)

아이디어는 각 단계에서 도착하여 규칙에 따라 처리되는 1 개 또는 2 개의 데이터 세트가 있다는 것입니다. 데이터 세트가 하나뿐이면 해당 작업이 해당 데이터 세트에 수행됩니다. (예를 들어 색인을 스캔하여 원하는 행을 파악하거나 데이터 세트를 필터링하거나 정렬합니다.) 두 데이터 세트가 두 개이면 더 들여 쓰기되는 두 가지가되고 표시되는 규칙에 따라 결합됩니다. 대부분의 규칙의 의미는 합리적으로 쉽게 추측 할 수 있지만 (특히 이전에 많은 설명 계획을 읽은 경우) 문서를 살펴 보거나 문구를 삽입하여 (쉽게) 개별 항목을 확인할 수 있습니다. Google과 EXPLAIN.

이것은 분명히 완전한 설명은 아니지만 일반적으로 원하는 것을 파악할 수있는 충분한 컨텍스트를 제공합니다. 예를 들어 실제 데이터베이스에서이 계획을 고려하십시오.

explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';

------------------------------------------------------------------------------------------------------------------------------------------------------------

 Merge Join  (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
   Merge Cond: (a.orderid = b.orderid)
   ->  Sort  (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
         Sort Key: a.orderid
         Sort Method:  quicksort  Memory: 1695kB
         ->  Bitmap Heap Scan on orderitemattribute a  (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
               Recheck Cond: ((attributeid)::text = 'display-album'::text)
               ->  Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
                     Index Cond: ((attributeid)::text = 'display-album'::text)
   ->  Sort  (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
         Sort Key: b.orderid
         Sort Method:  quicksort  Memory: 76kB
         ->  Bitmap Heap Scan on orderitem b  (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
               Recheck Cond: ((productid)::text = 'ModernBook'::text)
               ->  Bitmap Index Scan on id_orderitem_productid  (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
                     Index Cond: ((productid)::text = 'ModernBook'::text)
 Total runtime: 842.134 ms
(17 rows)

직접 읽어보고 이해가되는지 확인하십시오.

내가 읽은 것은 데이터베이스가 먼저 id_orderitem_productid인덱스를 사용하여 원하는 행을 찾은 orderitem다음 빠른 정렬을 사용하여 해당 데이터 집합을 정렬 한 다음 (데이터가 RAM에 맞지 않으면 사용되는 정렬이 변경됨)이를 따로 설정한다는 것입니다.

다음으로 스캔 orditematt_attributeid_idx하여 원하는 행을 찾은 orderitemattribute다음 빠른 정렬을 사용하여 해당 데이터 세트를 정렬합니다.

그런 다음 두 데이터 세트를 가져와 병합합니다. (병합 조인은 정렬 된 두 데이터 세트를 병렬로 이동하여 일치 할 때 조인 된 행을 내보내는 일종의 "압축"작업입니다.)

내가 말했듯이, 당신은 계획 내부 부분에서 외부 부분까지, 아래에서 위로 작업합니다.



13

PgAdmin 은 계획 설명을 그래픽으로 표시합니다. 둘 사이를 앞뒤로 전환하면 텍스트 표현의 의미를 이해하는 데 실제로 도움이 될 수 있습니다. 그러나 무엇을 할 것인지 알고 싶다면 항상 GUI를 사용할 수 있습니다.



0

pgadmin을 설치하면 텍스트 출력을 제공 할뿐만 아니라 무슨 일이 일어나고 있는지를 보여주는 필터, 정렬 및 하위 집합 병합을 표시하는 설명 버튼이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.