아래에 표시된 예는 다음의 테이블을 사용합니다.포스트그레SQL회귀 테스트 데이터베이스. 표시된 출력은 버전 8.3에서 가져온 것입니다. 이전(또는 이후) 버전의 동작은 다를 수 있습니다. 이후에도 참고하세요.분석통계를 생성하는 동안 무작위 샘플링을 사용하며 결과는 새로운 통계 이후 약간 변경됩니다.분석.
아주 간단한 쿼리부터 시작해 보겠습니다.
설명 선택 * FROM tenk1;
쿼리 계획
------------------------------------------------
tenk1의 시퀀스 스캔(비용=0.00..458.00행=10000너비=244)
계획자가 카디널리티를 결정하는 방법tenk1포함됨토토 사이트 순위 _, 그러나 완전성을 위해 여기서는 반복됩니다. 페이지 및 행 수는 다음에서 조회됩니다.pg_class:
pg_class WHERE relname = 'tenk1'에서 relpages, reltuples 선택;
렐페이지 | 리트플스
---------+------------
358 | 10000
이 숫자는 지난번 현재의 숫자입니다.진공또는분석테이블 위에. 그런 다음 플래너는 테이블의 실제 현재 페이지 수를 가져옵니다(이것은 테이블 스캔이 필요하지 않은 저렴한 작업입니다). 만약 그것이 다르다면relpages그런 다음reltuples현재 행 추정치에 도달하도록 그에 따라 크기가 조정됩니다. 위의 예에서 값은relpages최신이므로 행 추정치는 다음과 같습니다.reltuples.
범위 조건이 포함된 예로 넘어가겠습니다어디절:
설명 선택 * FROM tenk1 WHERE 고유1 < 1000;
쿼리 계획
--------------------------------------------------------------------------------
tenk1의 비트맵 힙 스캔(비용=24.06..394.64행=1007 너비=244)
조건 재확인: (unique1 < 1000)
- tenk1_unique1의 비트맵 인덱스 스캔(비용=0.00..23.80 행=1007 너비=0)
인덱스 조건: (unique1 < 1000)
계획자가 다음을 조사합니다.어디에서절 조건 및 연산자에 대한 선택 함수 조회<에pg_operator. 칼럼에 담겨있습니다.오프레스트, 이 경우 항목은scalarltsel.scalarltsel함수는 다음에 대한 히스토그램을 검색합니다.고유1frompg_statistic. 수동 쿼리의 경우 더 간단한 것을 보는 것이 더 편리합니다.pg_stats보기:
pg_stats에서 히스토그램_바운드 선택
WHERE 테이블 이름='tenk1' AND attname='unique1';
히스토그램_바운드
----------------------------
0,993,1997,3050,4040,5036,5957,7057,8029,9016,9995
다음으로 차지하는 히스토그램의 비율“< 1000”해결되었습니다. 이것이 선택성입니다. 히스토그램은 범위를 동일한 빈도 버킷으로 나누므로 우리가 해야 할 일은 값이 있는 버킷을 찾아 개수를 계산하는 것뿐입니다.부분그리고모두이전의 것들 중. 값 1000은 분명히 두 번째 버킷(993-1997)에 있습니다. 각 버킷 내부 값의 선형 분포를 가정하면 다음과 같이 선택성을 계산할 수 있습니다.
선택성 = (1 + (1000 - 버킷[2].min)/(버킷[2].max - 버킷[2].min))/num_buckets
= (1 + (1000 - 993)/(1997 - 993))/10
= 0.100697
즉, 하나의 전체 버킷에 두 번째의 선형 분수를 더한 후 버킷 수로 나눈 값입니다. 이제 예상 행 수는 선택성과 카디널리티의 곱으로 계산할 수 있습니다.텐크1:
행 = rel_cardinality * 선택성
= 10000 * 0.100697
= 1007(반올림)
다음으로 동등 조건이 있는 예를 고려해 보겠습니다.어디절:
EXPLAIN SELECT * FROM tenk1 WHERE stri롤 토토u1 = 'CRAAAA';
쿼리 계획
--------------------------------
tenk1의 시퀀스 스캔(비용=0.00..483.00행=30너비=244)
필터: (stri롤 토토u1 = 'CRAAAA'::name)
다시 기획자는 다음을 조사합니다.어디절 조건을 지정하고 다음에 대한 선택 함수를 찾습니다.=즉,eqsel. 동등 롤 토토의 경우 히스토그램은 유용하지 않습니다. 대신에가장 일반적인 값 (MCVs)는 선택성을 결정하는 데 사용됩니다. 나중에 유용할 추가 열과 함께 MCV를 살펴보겠습니다.
pg_stats에서 null_frac, n_distinct, Most_common_vals, Most_common_freqs 선택 WHERE 테이블 이름='tenk1' AND attname='stri롤 토토u1'; 널_분수 | 0 n_distinct | 676 가장_공통_값 | EJAAAA,BBAAAA,CRAAAA,FCAAAA,FEAAAA,GSAAAA,JOAAAA,MCAAAA,NAAAAA,WGAAAA
이후CRAAAAMCV 목록에 나타납니다. 선택성은 가장 일반적인 주파수 목록의 해당 항목일 뿐입니다(MCFs):
선택성 = mcf[3]
= 0.003
이전과 마찬가지로 예상 행 수는 카디널리티와 이것의 곱입니다.텐크1:
행 = 10000 * 0.003
= 30
이제 동일한 쿼리를 고려하지만 상수가 포함되지 않습니다.MCV목록:
설명 선택 * FROM tenk1 WHERE stri롤 토토u1 = 'xxx';
쿼리 계획
--------------------------------
tenk1의 시퀀스 스캔(비용=0.00..483.00행=15너비=244)
필터: (stri롤 토토u1 = 'xxx'::name)
이것은 완전히 다른 문제입니다: 값이 다음과 같을 때 선택성을 추정하는 방법아님에서MCV목록. 접근 방식은 값이 목록에 없다는 사실과 모든 항목에 대한 빈도에 대한 지식을 결합하는 것입니다.MCVs:
선택성 = (1 - 합계(mvf))/(num_distinct - num_mcv)
= (1 - (0.00333333 + 0.003 + 0.003 + 0.003 + 0.003 + 0.003 +
0.003 + 0.003 + 0.003 + 0.003))/(676 - 10)
= 0.0014559
즉, 다음에 대한 모든 주파수를 합산하십시오.MCVs를 하나에서 뺀 다음 수로 나눕니다.기타고유한 값. 이는 MCV가 아닌 열의 일부가 다른 모든 고유 값에 고르게 분포되어 있다고 가정하는 것과 같습니다. null 값이 없으므로 이에 대해 걱정할 필요가 없습니다(그렇지 않으면 분자에서 null 분수도 뺍니다). 그런 다음 예상 행 수는 평소와 같이 계산됩니다.
행 = 10000 * 0.0014559
= 15(반올림)
이전 예는고유1 < 1000무엇을 지나치게 단순화했나요scalarltsel정말 그렇습니다; 이제 MCV 사용의 예를 살펴보았으므로 좀 더 자세히 설명할 수 있습니다. 그 예는 지금까지는 정확했습니다. 왜냐하면고유1는 MCV가 없는 고유한 열입니다(분명히 다른 값보다 더 일반적인 값은 없습니다). 고유하지 않은 열의 경우 일반적으로 히스토그램과 MCV 목록이 모두 있습니다.히스토그램에는 MCV로 표시되는 열 모집단 부분이 포함되지 않습니다.. 더 정확한 추정이 가능하기 때문에 이런 방식으로 작업을 수행합니다. 이 상황에서scalarltsel조건을 직접 적용합니다(예:“< 1000”)을 MCV 목록의 각 값에 추가하고 조건이 참인 MCV의 빈도를 합산합니다. 이는 표에서 MCV 부분 내 선택성의 정확한 추정치를 제공합니다. 그런 다음 히스토그램을 위와 같은 방식으로 사용하여 테이블에서 MCV가 아닌 부분의 선택도를 추정한 다음 두 숫자를 결합하여 전체 선택도를 추정합니다. 예를 들어 다음을 고려하세요.
EXPLAIN SELECT * FROM tenk1 WHERE stri롤 토토u1 < 'IAAAAA';
쿼리 계획
----------------------------------
tenk1의 시퀀스 스캔(비용=0.00..483.00행=3077너비=244)
필터: (stri롤 토토u1 < 'IAAAAA'::name)
우리는 이미 다음에 대한 MCV 정보를 확인했습니다.stri롤 토토u1, 히스토그램은 다음과 같습니다.
pg_stats에서 히스토그램_바운드 선택
WHERE 테이블 이름='tenk1' AND attname='stri롤 토토u1';
히스토그램_바운드
--------------------------------------------------------------------------------
AAAAAA,CQAAAA,FRAAAA,IBAAAA,KRAAAA,NFAAAA,PSAAAA,SGAAAA,VAAAAA,XLAAAA,ZZAAAA
MCV 목록을 확인해보니 조건이 있는 것으로 나타났습니다.stri롤 토토u1 < 'IAAAAA'마지막 4개가 아닌 처음 6개 항목으로 만족하므로 모집단의 MCV 부분 내 선택성은 다음과 같습니다.
선택성 = 합계(관련 mvfs)
= 0.00333333 + 0.003 + 0.003 + 0.003 + 0.003 + 0.003
= 0.01833333
또한 모든 MCF를 합산하면 MCV로 표시되는 인구의 전체 비율이 0.03033333이므로 히스토그램으로 표시되는 비율은 0.96966667입니다(다시 말하지만 null은 없습니다. 그렇지 않으면 여기서 제외해야 합니다). 값이 있음을 알 수 있습니다.IAAAAA은 세 번째 히스토그램 버킷의 거의 끝 부분에 위치합니다. 다양한 문자의 빈도에 대한 다소 뻔한 가정을 사용하여 플래너는 다음보다 작은 히스토그램 모집단 부분에 대해 추정치 0.298387에 도달합니다.IAAAAA. 그런 다음 MCV 모집단과 비MCV 모집단에 대한 추정치를 결합합니다.
선택성 = mcv_selectivity + histogram_selectivity * histogram_fraction
= 0.01833333 + 0.298387 * 0.96966667
= 0.307669
행 = 10000 * 0.307669
= 3077(반올림)
이 특정 예에서는 열 분포가 실제로 매우 평평하기 때문에 MCV 목록의 수정 사항은 상당히 작습니다(이러한 특정 값이 다른 값보다 더 일반적이라고 표시하는 통계는 대부분 샘플링 오류로 인해 발생합니다). 일부 값이 다른 값보다 훨씬 더 일반적인 보다 일반적인 경우, 가장 일반적인 값에 대한 선택성이 정확하게 발견되므로 이 복잡한 프로세스는 정확도를 유용하게 향상시킵니다.
이제 하나 이상의 조건이 있는 경우를 고려해 보겠습니다.어디절:
설명 선택 * FROM tenk1 WHERE Unique1 < 1000 AND stri롤 토토u1 = 'xxx';
쿼리 계획
--------------------------------------------------------------------------------
tenk1의 비트맵 힙 스캔(비용=23.80..396.91행=1너비=244)
조건 재확인: (unique1 < 1000)
필터: (stri롤 토토u1 = 'xxx'::name)
- tenk1_unique1의 비트맵 인덱스 스캔(비용=0.00..23.80 행=1007 너비=0)
인덱스 조건: (unique1 < 1000)
플래너는 두 조건이 독립적이라고 가정하므로 절의 개별 선택성이 함께 곱해질 수 있습니다.
선택성 = 선택성(unique1 < 1000) * 선택성(stri롤 토토u1 = 'xxx')
= 0.100697 * 0.0014559
= 0.0001466
행 = 10000 * 0.0001466
= 1(반올림)
비트맵 인덱스 스캔에서 반환될 것으로 예상되는 행 수는 인덱스에 사용된 조건만 반영한다는 점에 유의하세요. 이는 후속 힙 가져오기에 대한 비용 추정에 영향을 미치기 때문에 중요합니다.
마지막으로 우리는 조인과 관련된 쿼리를 조사할 것입니다:
설명 선택 * tenk1 t1, tenk2 t2에서
t1.unique1 < 50 AND t1.unique2 = t2.unique2;
쿼리 계획
-------------------------------------------------------------------------
중첩 루프(비용=4.64..456.23행=50너비=488)
- tenk1 t1의 비트맵 힙 스캔(비용=4.64..142.17 행=50 너비=244)
조건 재확인: (unique1 < 50)
- tenk1_unique1의 비트맵 인덱스 스캔(비용=0.00..4.63행=50너비=0)
지수 조건: (고유1 < 50)
- tenk2 t2에서 tenk2_unique2를 사용한 인덱스 스캔(비용=0.00..6.27행=1너비=244)
인덱스 조건: (unique2 = t1.unique2)
제한사항tenk1, 고유1 < 50은 중첩 루프 조인 전에 평가됩니다. 이는 이전 범위 예제와 유사하게 처리됩니다. 이번에는 값 50이의 첫 번째 버킷에 속합니다.고유1히스토그램:
선택성 = (0 + (50 - 버킷[1].min)/(버킷[1].max - 버킷[1].min))/num_buckets
= (0 + (50 - 0)/(993 - 0))/10
= 0.005035
행 = 10000 * 0.005035
= 50(반올림)
조인 제한은 다음과 같습니다.t2.unique2 = t1.unique2. 교환원은 우리에게 친숙한 사람입니다.=, 그러나 선택성 함수는 다음에서 얻습니다.oprjoin열pg_operator그리고eqjoinsel. 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) / 최대(10000, 10000)
= 0.0001
이것은 각 관계에 대해 하나에서 null 분수를 빼고 고유한 값의 최대 개수로 나누는 것입니다. 조인이 내보낼 가능성이 있는 행 수는 두 입력의 데카르트 곱의 카디널리티에 선택성을 곱하여 계산됩니다.
행 = (outer_cardinality * inner_cardinality) * 선택성
= (50 * 10000) * 0.0001
= 50
두 열에 대한 MCV 목록이 있었다면,eqjoinselMCV 목록의 직접 비교를 사용하여 MCV로 표시되는 열 모집단 부분 내에서 조인 선택성을 결정했을 것입니다. 나머지 모집단에 대한 추정치는 여기에 표시된 것과 동일한 접근 방식을 따릅니다.
우리가 보여준 것을 주목하세요inner_cardinality10000, 즉 수정되지 않은 크기tenk2. 검사 결과 나타날 수 있습니다.설명조인 행의 추정치는 50 * 1에서 나오도록 출력합니다. 즉, 외부 행 수에 각 내부 인덱스 스캔으로 얻은 추정 행 수를 곱한 값입니다.tenk2. 그러나 이는 사실이 아닙니다. 조인 관계 크기는 특정 조인 계획을 고려하기 전에 추정됩니다. 모든 것이 제대로 작동하는 경우 조인 크기를 추정하는 두 가지 방법은 거의 동일한 답을 생성하지만 반올림 오류 및 기타 요인으로 인해 때때로 크게 분기됩니다.
더 자세한 내용에 관심이 있는 분들을 위해 테이블 크기 추정(모든 것 이전에)어디에서절)이 완료되었습니다.src/backend/optimizer/util/plancat.c. 조항 선택성에 대한 일반적인 논리는 다음과 같습니다.src/backend/optimizer/path/clausesel.c. 연산자별 선택성 함수는 주로 다음에서 찾을 수 있습니다.src/backend/utils/adt/selfuncs.c.