24

EXPLAIN ANALYZE 결과를 보는 데 익숙하지 않아 쿼리가 너무 느려서 큰 문제가 있습니다. 내가 설명 쿼리의 결과를 해석하는 방법을 읽으려고했지만, 내가 무엇을 찾고 있어야하는지, 그리고 무엇이 잘못 될지 모릅니다. 어딘가에 큰 빨간 불빛이 깜박 거리고 있다는 느낌이 들었습니다.EXPLAIN ANALYZE를 이해하는 방법

그래서 쿼리, 그것은 다음과 같이 아주 간단 보인다 :

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE LIMIT 25 OFFSET 0 

그리고이 같은 결과를 :

Limit (cost=0.00..161.07 rows=25 width=1245) (actual time=35.232..38.694 rows=25 loops=1) 
    -> Index Scan using index_cars_onsale_on_brand_and_model_name on cars (cost=0.00..1179.06 rows=183 width=1245) (actual time=35.228..38.652 rows=25 loops=1) 
     Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text)) 
     Filter: has_auto_gear" 
Total runtime: 38.845 ms 

약간의 배경 : 내가 PostgreSQL을 9.1.6에있어, Herokuus 전용 데이터베이스에서 실행됩니다. 내 DB는 aprox 7,5Gb RAM을 가지고 있으며, 테이블 카는 3,1M 행을 포함하고 행의 aprox 2,0M에는 sales_state = 'onsale'이 있습니다. 테이블에는 170 개의 열이 있습니다. 몇 가지 큰 명백한 문제를보고

CREATE INDEX index_cars_onsale_on_brand_and_model_name 
    ON cars 
    USING btree 
    (brand COLLATE pg_catalog."default" , model_name COLLATE pg_catalog."default") 
    WHERE sales_state::text = 'onsale'::text; 

사람 :이 사용하는 인덱스는 다음과 같이 보인다?

EDIT :

SELECT pg_relation_size('cars'), pg_total_relation_size('cars'); 

pg_relation_size : 2058444800 pg_total_relation_size : 4900126720

SELECT pg_relation_size('index_cars_onsale_on_brand_and_model_name'); 

pg_relation_size : 46,301,184

SELECT avg(pg_column_size(cars)) FROM cars limit 5000; 

평균 : 636.9732567210792995

제한없이 17,451,515,

:

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE 

Bitmap Heap Scan on cars (cost=12.54..1156.95 rows=183 width=4) (actual time=17.067..55.198 rows=2096 loops=1) 
    Recheck Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text) AND ((sales_state)::text = 'onsale'::text)) 
    Filter: has_auto_gear 
    -> Bitmap Index Scan on index_cars_onsale_on_brand_and_model_name (cost=0.00..12.54 rows=585 width=0) (actual time=15.211..15.211 rows=7411 loops=1)" 
     Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text)) 
Total runtime: 56.851 ms 
+0

는 진공 청소기로 청소하십시오 - http://www.postgresql.org/docs/8.1/static/maintenance.html. 쿼리 계획은 합리적인 것처럼 보이지만 시간은 분명 없습니다! –

+0

검색어를 실행하기 바로 전에 전체 진공도와 분석도 실행했습니다 ... 내 웹 사이트는 중고차의 검색 엔진이므로 타이밍이 훨씬 용납되지 않습니다. 내 목표는 총 시간을 1 초 미만으로 줄이는 것입니다. 그것이 가능하다고 생각하십니까? 아니면 합리적인 데이터베이스가 아닌 다른 기술을 찾아야합니까? –

+0

@NielsKristian 나는이 문제의 큰 부분이 "170 열"부분일지도 모른다고 생각한다. 테이블이 얼마나 큽니까? 'SELECT pg_relation_size ('cars'), pg_total_relation_size ('cars');'. 또한 인덱스 크기를 얻기 위해 SELECT pg_relation_size ('index_cars_onsale_on_brand_and_model_name'); 평균 행 너비는 얼마입니까? 'SELECT avg (pg_column_size (cars)) FROM 테스트 자동차 한도가 5000; ' –

답변

22

이 같은 간단한 계획 유용하지 동안은 http://explain.depesz.com 정말 유용합니다. http://explain.depesz.com/s/t4fi을 참조하십시오. '통계'탭과 '옵션'풀다운에 유의하십시오.

상황이이 계획에 대한주의 사항

  • 예상 행 수 (183)는 실제 행 수 (25) 합리적으로 비교할 수있다. 그것은 수백 배나 1도 아닙니다. 행 계수 추정 또는 "1 대 1 대"문제와 관련하여 더 많은 관심이 있습니다. (당신은 "정부 업무에 충분히 근접"의 정확성 - "군대 계약 회계에 충분히 근접"할 필요조차 없다). 선택도 추정 및 통계는 합리적인 것처럼 보입니다.

  • 제공된 두 열의 부분 색인 (index scan using index_cars_onsale_on_brand_and_model_name)을 사용하므로 부분 색인 조건과 일치합니다. 그걸 Filter: has_auto_gear에서 볼 수 있습니다. 인덱스 검색 조건도 표시됩니다.

  • 테이블의 행 수가 인덱스가 상당히 커야한다는 점을 고려하면 쿼리 성능이 상당히 좋아 보이며, 특히 두 개 이상의 열이있는 경우 쿼리 성능이 상당히 좋아집니다. 일치하는 행이 흩어지기 때문에 각 행마다 별도의 페이지 읽기가 필요합니다.

여기에 아무것도 없습니다. 그러나이 쿼리는 PostgreSQL 9.2의 인덱스 전용 검사에서 큰 이점을 얻을 수 있습니다.

여기에 테이블이 부 풀릴 수 있습니다. 그러나 2 열 인덱스와 완전한 행 수를 감안할 때 응답 시간이 완전히 비합리적이지는 않습니다. 특히 170 (!!) 열이 상대적으로 적합 할 가능성이있는 테이블의 경우 각 페이지에 몇 개의 튜플이 있습니다. 일부 가동 중지 시간을 감당할 수 있다면 VACUUM FULL을 사용하여 테이블을 재구성하고 인덱스를 다시 작성하십시오. 이렇게하면 테이블을 다시 빌드하는 동안 테이블을 잠 그게됩니다. 가동 중지 시간을 감당할 수 없다면 pg_reorg 및/또는 CREATE INDEX CONCURRENTLYALTER INDEX ... RENAME TO을 참조하십시오.

은 버퍼가 액세스 보여줄 수있는 당신은, 때때로 EXPLAIN (ANALYZE, BUFFERS, VERBOSE)이 더 많은 정보를 찾을 수 있습니다

등 (이 다소 다른 쿼리 둔화의 위험을 실행하지만) 빨리이 쿼리를 만들 수 있습니다

하나의 옵션은 테이블을 분할하는 것입니다 brand에 있고 constraint_exclusion을 사용하도록 설정하십시오. partitioning을 참조하십시오.

+0

안녕하세요. 설명을 주셔서 감사합니다. 쿼리를 실행하기 전에 전체 진공을 수행했습니다. –

+0

@NielsKristian 다른 모든 것은 실패합니다. 답변 편집을 참조하십시오. 또한,'EXPLAIN (ANALYZE, BUFFERS, VERBOSE)'결과를 보여주기 위해 질문을 편집하십시오. –

+0

모든 위대한 도움에 감사드립니다! 필자는 SQL 디버깅에 대한 많은 지식을 확실하게 얻었습니다. 이 솔루션은 테이블의 열 수를 줄이고 내가 선택한 항목을보다 정확하게 나타냅니다. 두 번째로 나는 더 잘 맞는 지표를 만들었습니다. –

0

음 ... 내가 말할 수있는 것은 데이터베이스가 (통계에서) 183 개의 행을 가져올 것으로 예상한다는 것입니다. 실제로 그것은 25 행을 얻고 있습니다. 이 경우에는 관련성이 적지 만 (즉, 이러한 작은 양과 많은 작업이 없기 때문에 잘못 추정하는 것에 대해 걱정할 필요가 없습니다.)

더 큰 문제 (imho)는 25 개의 행에 대한 간단한 색인 조회가 35ms가 소요된다는 것입니다. 그것은 조금은 보인다. 데이터베이스가 적어도 메모리의 모든 인덱스를 가질 정도로 무거울까요? 과도하지는 않지만 조금 느린 것 같습니다. 당신이 설명보고에 관해서는

, 나는 explain.depesz.com 사용하는 것이 좋습니다 것입니다 : http://explain.depesz.com/s/sA6

+0

ms가 아닌 35 개를 의미하지 않습니까? –

+0

@NielsKristian 나에게 밀리 초처럼 보입니다. 추측 하면 DE 스타일 표기법 (예 : "123.456.789,50"대신 US/AU/UK 스타일 "123,456,789.50")으로 읽는 것입니다. AFAIK Pg는 EXPLAIN ANALYZE에서 시간을 현지화하지 않으므로 35 밀리 초이어야합니다. –