이 장은 다음에서 다룬 내용을 바탕으로 작성되었습니다.섹션 13.1그리고토토 핫, 그리고 어떻게 플래너는 시스템 통계를 사용하여 행 수를 추정합니다. 쿼리의 각 단계가 반환될 수 있습니다. 이는 중요한 부분입니다. 계획/최적화 프로세스를 통해 많은 원시 정보 제공 비용 계산을 위한 자료입니다.
이 장의 목적은 코드를 문서화하는 것이 아닙니다 — 코드 자체에서 수행하는 것이 더 좋지만 방법에 대한 개요를 제시합니다. 작동합니다. 이것은 아마도 누군가의 학습 곡선을 완화할 것입니다. 나중에 코드를 읽고 싶은 사람. 그 결과, 선택한 접근 방식은 일련의 점진적인 분석을 더 많이 분석하는 것입니다. 복잡한 예.
아래에 표시된 출력 및 알고리즘은 버전에서 가져왔습니다. 8.0. 이전(또는 이후) 버전의 동작은 다를 수 있습니다.
회귀 테스트 데이터베이스에서 가져온 예를 토토 베이하여, 아주 간단한 쿼리부터 시작해 보겠습니다.
설명 선택 * FROM tenk1;
쿼리 계획
------------------------------------------------
tenk1의 시퀀스 스캔(비용=0.00..445.00행=10000너비=244)
계획자가 카디널리티를 결정하는 방법tenk1다음으로 덮여있습니다섹션 13.1, 하지만
완전성을 위해 여기에서 반복합니다. 행 수를 조회합니다.
에서pg_class:
pg_class WHERE relname = 'tenk1'에서 reltuples, relpages 선택;
렐페이지 | 리트플스
---------+------------
345 | 10000
플래너가 다음을 확인합니다relpages추정(이것은 저렴합니다. 작동) 잘못된 경우 크기가 조정될 수 있습니다.reltuples행 추정값을 얻으려면. 이에 그렇지 않은 경우에는 다음과 같습니다.
행 = 10000
범위 조건이 포함된 예로 넘어가겠습니다어디절:
설명 선택 * FROM tenk1 WHERE 고유1 < 1000;
쿼리 계획
----------------------------------
tenk1의 시퀀스 스캔(비용=0.00..470.00행=1031너비=244)
필터: (고유1 < 1000)
기획자가 다음을 조사합니다.어디절 조건:
고유1 < 1000
그리고 연산자에 대한 제한 함수를 찾습니다<에pg_operator. 칼럼에 담겨있습니다.오프레스트, 결과는 다음과 같습니다.
경우는scalarltsel.scalarltsel함수 검색
히스토그램고유1frompg_statistics- 우리는 따라갈 수 있어요
더 간단한 방법을 토토 베이하여 이 작업을 수행합니다.pg_stats보기:
pg_stats에서 히스토그램_바운드 선택
WHERE 테이블 이름='tenk1' AND attname='unique1';
히스토그램_바운드
----------------------------
1,970,1943,2958,3971,5069,6028,7007,7919,8982,9995
다음으로 차지하는 히스토그램의 비율"< 1000"해결되었습니다. 이것은 선택성. 히스토그램은 범위를 동일하게 나눕니다. 빈도 버킷이 있으므로 우리가 해야 할 일은 버킷을 찾는 것뿐입니다. 우리의 가치는 중요합니다부분그리고전체이전의 것들 중. 가치 1000은 분명히 두 번째(970 - 1943) 버킷에 있으므로 각 버킷 내 값의 선형 분포를 가정하면 선택성을 다음과 같이 계산할 수 있습니다.
선택성 = (1 + (1000 - bckt[2].min)/(bckt[2].max - bckt[2].min))/num_bckts
= (1 + (1000 - 970)/(1943 - 970))/10
= 0.1031
즉, 하나의 전체 버킷에 선형 분수를 더한 것입니다.
둘째, 버킷 수로 나눕니다. 추정 수
이제 선택도의 곱으로 행을 계산할 수 있습니다.
및 카디널리티텐크1:
행 = rel_cardinality * 선택성
= 10000 * 0.1031
= 1031
다음으로 동등 조건이 있는 예를 고려해 보겠습니다. 그어디절:
EXPLAIN SELECT * FROM tenk1 WHERE stringu1 = 'ATAAAA';
쿼리 계획
--------------------------------
tenk1의 시퀀스 스캔(비용=0.00..470.00행=31너비=244)
필터: (stringu1 = 'ATAAAA'::이름)
다시 기획자는 다음을 조사합니다.어디에서절 조건:
stringu1 = 'ATAAAA'
그리고 다음에 대한 제한 기능을 찾습니다=즉,eqsel.
이 경우는 가장 일반적인 값이므로 약간 다릅니다 —MCVs는 다음을 결정하는 데 사용됩니다.
선택성. 몇 가지 추가 사항을 포함하여 다음을 살펴보겠습니다.
나중에 유용할 열:
pg_stats에서 null_frac, n_distinct, Most_common_vals, Most_common_freqs 선택 WHERE 테이블 이름='tenk1' AND attname='stringu1'; 널_분수 | 0 n_distinct | 672 가장_공통_값 | FDAAAA,NHAAAA,ATAAAA,BGAAAA,EBAAAA,MOAAAA,NDAAAA,OWAAAA,BHAAAA,BJAAAA
선택성은 단지 가장 일반적인 주파수일 뿐입니다 (MCF)에 해당 세 번째MCV— 'ATAAAA':
선택성 = mcf[3]
= 0.003
예상 행 수는 이것의 곱입니다.
카디널리티 포함텐크1다음과 같이
이전:
행 = 10000 * 0.003
= 30
표시된 숫자설명이다 일부 사후 추정 확인으로 인해 이보다 하나 더 있습니다.
이제 동일한 쿼리를 고려하지만 다음과 같지 않은 상수를 사용합니다. 에서MCV목록:
EXPLAIN SELECT * FROM tenk1 WHERE stringu1 = 'xxx';
쿼리 계획
--------------------------------
tenk1의 시퀀스 스캔(비용=0.00..470.00행=15너비=244)
필터: (stringu1 = 'xxx'::name)
이것은 상당히 다른 문제입니다. 어떻게 추정할 것인가? 값이 다음과 같을 때의 선택성아님에서MCV목록. 접근 방식은 사실을 이용하는 것입니다. 해당 값이 목록에 없으며 지식과 결합되어 있음 모든 것에 대한 주파수 중MCVs:
선택성 = (1 - 합계(mvf))/(num_distinct - num_mcv)
= (1 - (0.00333333 + 0.00333333 + 0.003 + 0.003 + 0.003
+ 0.003 + 0.003 + 0.003 + 0.00266667 + 0.00266667))/(672 - 10)
= 0.001465
즉, 다음에 대한 모든 주파수를 합산하십시오.MCVs를 하나에서 빼세요 — 왜냐하면 그것은아님다음 중 하나 이것을 다음과 같이 나눕니다.나머지고유한 값. 공지사항 null 값이 없으므로 걱정할 필요가 없습니다. 그. 예상 행 수는 평소와 같이 계산됩니다.
행 = 10000 * 0.001465
= 15
더 많은 사례를 고려하기 위해 복잡성을 증가시키자 에서 하나 이상의 조건어디절:
설명 선택 * FROM tenk1 WHERE Unique1 < 1000 AND stringu1 = 'xxx';
쿼리 계획
----------------------------------------------
tenk1의 시퀀스 스캔(비용=0.00..495.00행=2너비=244)
필터: ((unique1 < 1000) AND (stringu1 = 'xxx'::name))
독립성을 가정하고 선택성을 높였습니다. 개별 제한 사항이 함께 곱해집니다.
선택성 = 선택성(unique1 < 1000) * 선택성(stringu1 = 'xxx')
= 0.1031 * 0.001465
= 0.00015104
행 추정값은 이전과 같이 계산됩니다:
행 = 10000 * 0.00015104
= 2
마지막으로 다음을 포함하는 쿼리를 조사하겠습니다.가입함께어디절:
설명 선택 * tenk1 t1, tenk2 t2에서
t1.unique1 < 50 AND t1.unique2 = t2.unique2;
쿼리 계획
---------------------------------------------------------------
중첩 루프(비용=0.00..346.90행=51너비=488)
- tenk1 t1에서 tenk1_unique1을 사용한 인덱스 스캔(비용=0.00..192.57 행=51 너비=244)
지수 조건: (고유1 < 50)
- tenk2 t2에서 tenk2_unique2를 사용한 인덱스 스캔(비용=0.00..3.01 행=1 너비=244)
인덱스 조건: ("outer".unique2 = t2.unique2)
제한사항tenk1
"고유1 < 50"평가됨
중첩 루프 조인 전에. 이는 다음과 유사하게 처리됩니다.
이전 범위의 예. 에 대한 제한 연산자<isscalarlteqsel전과 같지만 이번에는
값 50은의 첫 번째 버킷에 있습니다.고유1히스토그램:
선택성 = (0 + (50 - bckt[1].min)/(bckt[1].max - bckt[1].min))/num_bckts
= (0 + (50 - 1)/(970 - 1))/10
= 0.005057
행 = 10000 * 0.005057
= 51
조인 제한사항은 다음과 같습니다.
t2.unique2 = t1.unique2
이것은 조인 방법이 중첩 루프이기 때문입니다.tenk1외부 루프에 있습니다.
교환원은 우리에게 친숙한 사람입니다.=,
그러나 제한 기능은 다음에서 얻습니다.oprjoin열pg_operator- 그리고는eqjoinsel. 추가적으로 우리는
둘 다에 대한 통계 정보tenk2그리고tenk1:
pg_stats에서 테이블 이름, null_frac,n_distinct, Most_common_vals 선택
WHERE 테이블 이름 IN ('tenk1', 'tenk2') AND attname='unique2';
테이블 이름 | 널_분수 | n_distinct | 가장_공통_발
---------+------------+------------+----
텐크1 | 0 | -1 |
텐크2 | 0 | -1 |
이 경우에는 없습니다MCV정보고유2모든 값이 다음과 같이 나타나기 때문입니다. 고유하므로 우리는 오직 다음에만 의존하는 알고리즘을 사용할 수 있습니다. 두 관계에 대한 고유 값의 수 null 분수:
선택성 = (1 - null_frac1) * (1 - null_frac2) * min(1/num_distinct1, 1/num_distinct2)
= (1 - 0) * (1 - 0) * 최소(1/10000, 1/1000)
= 0.0001
이것은 각 항목에 대해 하나에서 null 분수를 빼는 것입니다. 관계를 구별하고 두 개의 별개의 최대값으로 나눕니다. 가치. 조인이 방출할 가능성이 있는 행 수는 다음과 같습니다. 두 개의 데카르트 곱의 카디널리티로 계산됩니다. 중첩 루프의 노드에 선택성을 곱합니다.
행 = (outer_cardinality * inner_cardinality) * 선택성
= (51 * 10000) * 0.0001
= 51
더 자세한 내용에 관심이 있는 분들을 위해 관계의 행 수는 다음과 같습니다.src/backend/optimizer/util/plancat.c. 는 조항 선택성에 대한 계산 논리는 다음과 같습니다.src/backend/optimizer/path/clausesel.c. 는 연산자의 실제 구현 및 조인 제한 함수는에서 찾을 수 있습니다.src/backend/utils/adt/selfuncs.c.