2016-10-28 3 views
0

여러 조인을 수행하는 쿼리가 있습니다. 나는 결과에서 최신 인 각 키워드의 단지 위치를 얻는 것을 시도한다.포스트 그레스 2 열 정렬 낮은 성능

Unique (cost=73673.65..76630.38 rows=264 width=40) (actual time=30777.117..49143.023 rows=259 loops=1) 
     -> Sort (cost=73673.65..75152.02 rows=591347 width=40) (actual time=30777.116..47352.373 rows=10891486 loops=1) 
      Sort Key: p.keyword_id, p.created_at DESC 
      Sort Method: external merge Disk: 512672kB 
      -> Merge Join (cost=219.59..812.26 rows=591347 width=40) (actual time=3.487..3827.028 rows=10891486 loops=1) 
        Merge Cond: (w.parent_id = k.website_id) 
        -> Nested Loop (cost=128.46..597.73 rows=1268 width=44) (actual time=3.378..108.915 rows=61582 loops=1) 
         -> Nested Loop (cost=2.28..39.86 rows=1 width=28) (actual time=0.026..0.216 rows=7 loops=1) 
           -> Index Scan using index_websites_on_parent_id on websites w (cost=0.14..15.08 rows=4 width=28) (actual time=0.004..0.023 rows=7 loops=1) 
            Index Cond: (parent_id IS NOT NULL) 
           -> Bitmap Heap Scan on accounts a (cost=2.15..6.18 rows=1 width=4) (actual time=0.019..0.020 rows=1 loops=7) 
            Recheck Cond: (id = w.account_id) 
            Filter: ((amount > '0'::numeric) AND (round((amount/(payment_renewal_period)::numeric), 2) >= '1'::numeric) AND (round((amount/(payment_renewal_period)::numeric), 2) <= '19'::numeric)) 
            Heap Blocks: exact=7 
            -> Bitmap Index Scan on accounts_pkey (cost=0.00..2.15 rows=1 width=0) (actual time=0.006..0.006 rows=1 loops=7) 
              Index Cond: (id = w.account_id) 
         -> Bitmap Heap Scan on positions p (cost=126.18..511.57 rows=4631 width=16) (actual time=0.994..8.226 rows=8797 loops=7) 
           Recheck Cond: (website_id = w.parent_id) 
           Heap Blocks: exact=1004 
           -> Bitmap Index Scan on index_positions_on_5_columns (cost=0.00..125.02 rows=4631 width=0) (actual time=0.965..0.965 rows=8797 loops=7) 
            Index Cond: (website_id = w.parent_id) 
        -> Sort (cost=18.26..18.92 rows=264 width=4) (actual time=0.106..1013.966 rows=10891487 loops=1) 
         Sort Key: k.website_id 
         Sort Method: quicksort Memory: 37kB 
         -> Seq Scan on keywords k (cost=0.00..7.64 rows=264 width=4) (actual time=0.005..0.039 rows=263 loops=1) 
    Planning time: 1.081 ms 
    Execution time: 49184.222 ms 

내가 w.id 대신에 w.parent_id으로 쿼리를 실행할 때 건은이 위치를 부품 전체를 조인 다음과 같이 해당 쿼리가에 대한 비용

SELECT DISTINCT ON (p.keyword_id) 
    a.id  AS account_id, 
    w.parent_id AS parent_id, 
    w.name  AS name, 
    p.position AS position 
FROM websites w 
    JOIN accounts a ON w.account_id = a.id 
    JOIN keywords k ON k.website_id = w.parent_id 
    JOIN positions p ON p.website_id = w.parent_id 
WHERE a.amount > 0 AND w.parent_id NOTNULL AND (round((a.amount/a.payment_renewal_period), 2) BETWEEN 1 AND 19) 
ORDER BY p.keyword_id, p.created_at DESC; 

계획 : 여기

쿼리입니다 비용이 감소하여

Unique (cost=3621.07..3804.99 rows=264 width=40) (actual time=128.430..139.550 rows=259 loops=1) 
    -> Sort (cost=3621.07..3713.03 rows=36784 width=40) (actual time=128.429..135.444 rows=40385 loops=1) 
     Sort Key: p.keyword_id, p.created_at DESC 
     Sort Method: external sort Disk: 2000kB 
     -> Merge Join (cost=128.73..831.59 rows=36784 width=40) (actual time=25.521..63.299 rows=40385 loops=1) 
       Merge Cond: (k.website_id = w.id) 
       -> Index Only Scan using index_keywords_on_website_id_deleted_at on keywords k (cost=0.27..24.23 rows=264 width=4) (actual time=0.137..0.274 rows=263 loops=1) 
        Heap Fetches: 156 
       -> Materialize (cost=128.46..606.85 rows=1268 width=44) (actual time=3.772..49.587 rows=72242 loops=1) 
        -> Nested Loop (cost=128.46..603.68 rows=1268 width=44) (actual time=3.769..30.530 rows=61582 loops=1) 
          -> Nested Loop (cost=2.28..45.80 rows=1 width=32) (actual time=0.047..0.204 rows=7 loops=1) 
           -> Index Scan using websites_pkey on websites w (cost=0.14..21.03 rows=4 width=32) (actual time=0.007..0.026 rows=7 loops=1) 
             Filter: (parent_id IS NOT NULL) 
             Rows Removed by Filter: 4 
           -> Bitmap Heap Scan on accounts a (cost=2.15..6.18 rows=1 width=4) (actual time=0.018..0.019 rows=1 loops=7) 
             Recheck Cond: (id = w.account_id) 
             Filter: ((amount > '0'::numeric) AND (round((amount/(payment_renewal_period)::numeric), 2) >= '1'::numeric) AND (round((amount/(payment_renewal_period)::numeric), 2) <= '19'::numeric)) 
             Heap Blocks: exact=7 
             -> Bitmap Index Scan on accounts_pkey (cost=0.00..2.15 rows=1 width=0) (actual time=0.004..0.004 rows=1 loops=7) 
              Index Cond: (id = w.account_id) 
          -> Bitmap Heap Scan on positions p (cost=126.18..511.57 rows=4631 width=16) (actual time=0.930..2.341 rows=8797 loops=7) 
           Recheck Cond: (website_id = w.parent_id) 
           Heap Blocks: exact=1004 
           -> Bitmap Index Scan on index_positions_on_5_columns (cost=0.00..125.02 rows=4631 width=0) (actual time=0.906..0.906 rows=8797 loops=7) 
             Index Cond: (website_id = w.parent_id) 
Planning time: 1.124 ms 
Execution time: 157.167 ms 

웹상의 색인 이 정렬은 매우 빠르다는 것을 거의 놀랍도록 위치에 위치

Indexes: 
    "websites_pkey" PRIMARY KEY, btree (id) 
    "index_websites_on_account_id" btree (account_id) 
    "index_websites_on_deleted_at" btree (deleted_at) 
    "index_websites_on_domain_id" btree (domain_id) 
    "index_websites_on_parent_id" btree (parent_id) 
    "index_websites_on_processed_at" btree (processed_at) 

인덱스

Indexes: 
    "positions_pkey" PRIMARY KEY, btree (id) 
    "index_positions_on_5_columns" UNIQUE, btree (website_id, keyword_id, created_at, engine_id, region_id) 
    "overlap_index" btree (keyword_id, created_at) 
+0

'explain (analyze) '을 사용하여 생성 된 실행 계획을 보여주십시오. –

+0

parent_id 속성을 사용 하시겠습니까? 나는 시도 할 것이지만 쿼리가 끝날 때 확실하지 않다 ... – Robs

+0

@a_horse_with_no_name 질문을 업데이트했습니다. 또한,'explain analyze' 정보를 제공했지만 적은 데이터로 db에서이 작업을 수행해야했습니다. – Robs

답변

1

EXPLAIN 출력은보다 200 배 더 적은 열을 나타낸다.

두 경우 모두 정렬이 디스크로 유출됩니다 (Sort Method: external merge Disk: ...kB). work_mem을 올림으로써 메모리에 정렬을 유지할 수 있다면 이 더 빠를 것입니다.
하지만 첫 번째 정렬이 너무 커서 메모리에 맞출 수 없습니다.

아이디어는 쿼리 속도를 :

  • positions에 대한 (keyword_id, created_at)에 인덱스. 그게 도움이되는지 확실하지 않습니다.

  • 같이, 먼저 필터링을 수행

SELECT 
    a.id  AS account_id, 
    w.parent_id AS parent_id, 
    w.name  AS name, 
    p.position AS position 
FROM (SELECT DISTINCT ON (keyword_id) 
     positions, 
     website_id, 
     keyword_id, 
     created_at 
     FROM positions 
     ORDER BY keyword_id, created_at DESC) p 
    JOIN ... 
WHERE ... 
ORDER BY p.keyword_id, p.created_at DESC; 
:
DISTINCT ON은하지 ORDER BY SELECT 목록의 값을하기 때문에, 다소 이상한, 그래서 결과 값은 잘 정의되지 않았다.

+0

그래, 방금 전에 깨달은거야. 불행히도, 여러분이 작성한 것처럼 여기에 work_mem을 올리는 것은 의미가 없습니다 (예제는 개발 결과뿐입니다). 그러나 일부 추가/특정 인덱스를 사용하여 쿼리를 조정할 수있는 기회가 있습니까? – Robs

+0

확장 된 답변. –

+0

아이디어를 제공해 주셔서 감사합니다. – Robs