2014-02-24 1 views
3

가 ...이 대신 DBA.stackexchange.com에 게시해야하는지 알려포스트 그레스는

하자 테이블 인덱스를 사용하지 보인다 I가 다음 쿼리 :

SELECT DISTINCT "court_cases".* 
FROM "court_cases" 
LEFT OUTER JOIN service_of_processes 
    ON service_of_processes.court_case_id = court_cases.id 
LEFT OUTER JOIN jobs 
    ON jobs.service_of_process_id = service_of_processes.id 
WHERE 
    (jobs.account_id = 250093 
    OR court_cases.account_id = 250093) 
ORDER BY 
    court_cases.court_date DESC NULLS LAST, 
    court_cases.id DESC 
LIMIT 30 
OFFSET 0; 

그러나 실행하는 데 2-4 초가 걸리며 웹 응용 프로그램에서는 단일 쿼리에 대해 받아 들일 수 없습니다. (외래 키 관계에있는 인덱스 포함) 여기 http://explain.depesz.com/s/Yn6

테이블 정의 쿼리에 관련된 사람들 테이블 : on the PostgreSQL wiki을 제안하고, 여기에 결과를 뒀다로

나는 쿼리에 EXPLAIN (ANALYZE, BUFFERS)를 실행

http://sqlfiddle.com/#!15/114c6

WHERE 절이 서로 다른 두 테이블에서 쿼리하기 때문에 인덱스를 사용하는 데 문제가 있습니까? 이 인덱스를 실행하기 위해 쿼리에 어떤 종류의 인덱스 또는 변경을 할 수 있습니까?

PSQL=# select count(*) from service_of_processes; 
count 
-------- 
103787 
(1 row) 

PSQL=# select count(*) from jobs; 
count 
-------- 
108995 
(1 row) 

PSQL=# select count(*) from court_cases; 
count 
------- 
84410 
(1 row) 

편집 :

문제의 테이블의 현재 크기입니다 그 중요한 경우 내가, PostgreSQL을 9.3.1에 있어요.

답변

2

or 절을 사용하면 쿼리를 쉽게 최적화 할 수 없습니다. 한 가지 아이디어는 쿼리의 두 부분을 두 개의 개별 하위 쿼리로 분할하는 것입니다. 이것은 실제로 그들 중 하나를 많이 단순화합니다 (court_cases.account_id에있는 것).

(SELECT cc.* 
FROM "court_cases" cc 
WHERE cc.account_id = 250093 
ORDER BY cc.court_date DESC NULLS LAST, 
      cc.id DESC 
LIMIT 30 
) UNION ALL 
(SELECT cc.* 
FROM "court_cases" cc LEFT OUTER JOIN 
     service_of_processes sop 
     ON sop.court_case_id = cc.id LEFT OUTER JOIN 
     jobs j 
     ON j.service_of_process_id = sop.id 
WHERE (j.account_id = 250093 AND cc.account_id <> 250093) 
ORDER BY cc.court_date DESC NULLS LAST, id DESC 
LIMIT 30 
) 
ORDER BY court_date DESC NULLS LAST, 
     id DESC 
LIMIT 30 OFFSET 0; 

을 그리고 다음 인덱스를 추가 :

이 버전을 시도해보십시오 두 번째 쿼리는 중복 레코드를 방지하기 and cc.count_id <> 250093를 사용

create index court_cases_accountid_courtdate_id on court_cases(account_id, court_date, id); 
create index jobs_accountid_sop on jobs(account_id, service_of_process_id); 

하는 것으로. 따라서 distinct 또는 union (union all 제외)을 사용할 필요가 없습니다.

+0

마지막으로 작성한 인덱스에서 구문 오류가 발생했습니다. 인덱스의 이름이 누락되었습니다. 'on'.'jobs (account_id, service_of_process_id)에 인덱스 생성 jobs_account_id_sop_id;와 같은 것이어야합니다. – nzifnab

0

나는 다음과 같이 쿼리 수정하려고합니다 :

SELECT DISTINCT "court_cases".* 
FROM "court_cases" 
LEFT OUTER JOIN service_of_processes 
    ON service_of_processes.court_case_id = court_cases.id 
LEFT OUTER JOIN jobs 
    ON jobs.service_of_process_id = service_of_processes.id and jobs.account_id = 250093 
WHERE 
    (court_cases.account_id = 250093) 
ORDER BY 
    court_cases.court_date DESC NULLS LAST, 
    court_cases.id DESC 
LIMIT 30 
OFFSET 0; 

내가 문제가 필터가 제대로 쿼리 계획 최적화, 정말 이상한 성능 버그에 의해 분해되지 않는 사실이라고 생각을

+0

이것은 작동하지 않습니다 : \ 그것은'jobs.account_id = 250093'이지만'court_cases.account_id! = 250093' 인 법원의 경우를 포함하지 않으므로 원래 쿼리에'OR'이있었습니다 : ( – nzifnab

+0

맞아요 ... 사실 문제는 테이블이 크기 때문에 오랜 시간을 요청할 수있는 전체 조인 집합의 계산 후에 만 ​​where 조건을 평가할 수 있다는 것입니다. 인덱스 문제는 아닙니다. .. 두 개의 하위 쿼리에서 쿼리를 분해하고 where 필터를 분할 한 다음 두 쿼리의 합집합에서 select 별색을 적용합니다. – morepaolo