2013-12-17 3 views
0

에 레일/포스트 그레스 많은 최적화 : (예 : 페이지로드), I 정렬, 조회 및 페이지를 매기는해야합니다 자주 내가 같이 보이는 많은 관계로 많은이 많은 쿼리

class Feed 
    has_many :cross_listed_papers, through: :cross_lists, source: :paper 
end 

주어진 기간 동안 일련의 피드에 대해 교차 목록에있는 논문. 그러나, 이는 매우 느릴 수

[107] 지레 (주)> Paper.includes (: cross_lists) 어디에요 (cross_lists {FEED_ID : 311,312,313,314]}) 여기서 ("pubDate의> =.? and pubdate < =? ", Time.now - 300.days, Time.now) .count

D, [2013-12-17T21 : 56 : 43.640283 # 19404] DEBUG - : (228.9ms) SELECT COUNT "id"어디에서 "cross_lists". "feed_id"IN (311, 312, "ID") "문서"FR "서류"에서 왼쪽 외부 조인 "십자가 목록" 313, 314) AND (pubdate> = '2013-02-20 10 : 56 : 43.404072'and pubdate < = '2013-12-17 10 : 56 : 43.404234') => 2811

228.9ms는 모든 페이지로드에서 일어날 수있는 문제에 이상적이지 않습니다. 특히 더 적은 시간 범위에서 더 많은 데이터를 조인하려고하면 급증합니다.

Aggregate (cost=110771.10..110771.11 rows=1 width=4) (actual time=243.826..243.826 rows=1 loops=1) 
    -> Hash Join (cost=95343.72..110749.09 rows=8807 width=4) (actual time=93.725..242.725 rows=2830 loops=1) 
     Hash Cond: (cross_lists.paper_id = papers.id) 
     -> Bitmap Heap Scan on cross_lists (cost=2876.53..15182.11 rows=158372 width=4) (actual time=15.496..90.232 rows=162981 loops=1) 
       Recheck Cond: (feed_id = ANY ('{311,312,313,314}'::integer[])) 
       -> Bitmap Index Scan on index_cross_lists_on_feed_id_and_cross_list_date (cost=0.00..2836.94 rows=158372 width=0) (actual time=14.383..14.383 rows=162981 loops=1) 
        Index Cond: (feed_id = ANY ('{311,312,313,314}'::integer[])) 
     -> Hash (cost=91670.95..91670.95 rows=48499 width=4) (actual time=76.079..76.079 rows=48853 loops=1) 
       Buckets: 4096 Batches: 2 Memory Usage: 861kB 
       -> Bitmap Heap Scan on papers (cost=1033.46..91670.95 rows=48499 width=4) (actual time=6.495..61.230 rows=48853 loops=1) 
        Recheck Cond: ((pubdate >= '2013-02-20'::date) AND (pubdate <= '2013-12-17'::date)) 
        -> Bitmap Index Scan on index_papers_on_pubdate (cost=0.00..1021.34 rows=48499 width=0) (actual time=5.437..5.437 rows=48855 loops=1) 
          Index Cond: ((pubdate >= '2013-02-20'::date) AND (pubdate <= '2013-12-17'::date)) 
Total runtime: 244.295 ms 

나는 이러한 종류의 쿼리 속도를하는 데 사용할 수있는 인덱스가, 또는 내가 비정규 화에 의지해야합니까 다음은 분석 EXPLAIN이야?

+0

당신이 게시하고 분석 한 쿼리가 귀하의 루비 코드와 일치하지 않거나, 루비 코드가 원하는대로되지 않을 수도 있습니다 : 계획에 정렬 연산자가 없습니다. 당신이 세고 있기 때문에 유효 합니다만, 당신의 논리에 오류가 있음을 암시합니다. –

+0

좋은 지적.질문이 업데이트됩니다. –

답변

0

매우 비정상적인 것으로 결정했습니다. 대신 cross_lists 테이블에 pubDate의 이동에 의해, 내가 ~ 10 배의 속도 향상을 얻을 :

[185] 놀리려는 (주)> Paper.joins (: cross_lists)? 어디에요 ("(IN cross_lists.feed_id) 및 ? cross_lists.cross_list_date> = 및 cross_lists.cross_list_date < =? - 논문 "내부 조인", feed_ids, Time.now 300.days, Time.now는)

(22.4ms) SELECT COUNT (*) FROM

을 .count " "cross_lists"ON "cross_lists". "paper_id"= "papers". "id"WHERE (cross_lists.feed_id IN (311,312,313,314) AND cross_lists.cross_list_date> = '2013-02-20 14 : 33 : 29.034243'AND cross_lists.cross_list_date < = '2013-12-17 14 : 33 : 29.034443') => 2830

그러면이 쿼리의 결과에 페이지 매김을 적용하고 다른 데이터 사후 제한에 참여할 수 있으므로 큰 결과 집합의 영향이 크게 줄어 듭니다.

1

쿼리 계획이 정상적으로 보입니다. 플래너가 수행 한 선택 사항에서 알 수 있듯이 이미 가능한 최선의 색인을 사용하고 있습니다 (예 : 비트 맵 색인 스캔).

163k 행의 49k 행을 결합하는 데 걸리는 시간은 무엇입니까? 귀하의 기준 중 어떤 것도 미리 집계 될 수 없다는 것을 보면서 그것에 관해 할 수있는 것은 거의 없습니다.

질문 실제로 쿼리를 자주 실행하는 합리적인 질문입니다. 총 페이지 수를 계산하려면 이것이 실행 된 것 같습니다. 그렇다면 번호가 변경 될 때까지 캐시 할 수 없습니까? (그렇지 않은 경우 더 많은 정보를 게시하고 일반 영어로 쿼리가 달성하고자하는 것을 설명하십시오.)

+0

나는 그것을 두려워했다. 적극적인 캐싱이가는 길입니다. 아무도 아무 것도 나오지 않으면 대답을 수락합니다. –

관련 문제