2014-07-14 3 views
0

POSTGRES 9.1에서 실행중인 sql-query가 있습니다. 이 쿼리는 24 개의 LEFT JOIN을 사용합니다. 조인 된 모든 테이블은 이전 테이블과 관련하여 1 - 10-15 개의 데이터 행을 가질 수 있습니다.POSTGRES는 조인 된 테이블의 데이터를 집계합니다.

SELECT 
    asw.surname, 
    asw.firstname, 
    asw.fathername, 
    asw.birthday, 
    asbe.institue_title, 
    asht.honour_type 
    /* Other fields are hidden to simplify example */ 
FROM 
    /* Table of staff */ 
    agency_socworker AS asw 
LEFT JOIN 
    /* Table contains staff honours */ 
    agency_socworkerhonours AS ash 
    ON asw.id = ash.socworker_id 
LEFT JOIN 
    /* Table contains name of the certain honour_id */ 
    agency_socworker_honourtype AS asht 
    ON ash.honour_name_id = asht.id 
LEFT JOIN 
    /* Table contains education data */ 
    agency_socworker_base_edu AS asbe 
    ON asbe.socworker_id = asw.id 
/* Other part of query is hidden to simplify example */ 
ORDER BY 
    asw.surname ASC 

결과 예 :

surname---firstname---fathername---birthday-----honour_type----institue_title1 
Surname---firstname---fathername---1965-01-01---TYPE1----------institue_title1 
Surname---firstname---fathername---1965-01-01---TYPE2----------institue_title1 
Surname---firstname---fathername---1965-01-01---TYPE3----------institue_title1 
Surname---firstname---fathername---1965-01-01---TYPE4----------institue_title1 
Surname---firstname---fathername---1965-01-01---TYPE5----------institue_title1 

Surname---firstname---fathername---1965-01-01---TYPE1----------institue_title2 
Surname---firstname---fathername---1965-01-01---TYPE2----------institue_title2 
Surname---firstname---fathername---1965-01-01---TYPE3----------institue_title2 
Surname---firstname---fathername---1965-01-01---TYPE4----------institue_title2 
Surname---firstname---fathername---1965-01-01---TYPE5----------institue_title2 

내가 원하는 SQL 쿼리의 결과로 나는 1 개 값

SQL 쿼리의 예에 의해 서로 다른, 매우 많은 데이터 행이 다음을 얻을 :

surname---firstname---fathername---birthday--------honour_type----------------------institue_title 
Surname---firstname---fathername---1965-01-01---TYPE1, TYPE2, TYPE3, TYPE4, TYPE5---institue_title1, institue_title2 

나는이 목표를 달성하기 위해 array_agg 기능을 사용 :

SELECT 
    asw.surname, 
    asw.firstname, 
    asw.fathername, 
    asw.birthday, 
    array_agg(asbe.institue_title) AS honour_type 
    array_agg(asht.honour_type) AS honour_type 
    /* Other fields are hidden to simplify example */ 
    FROM 
     /* Table of staff */ 
     agency_socworker AS asw 
    LEFT JOIN 
     /* Table contains staff honours */ agency_socworkerhonours AS ash 
     ON asw.id = ash.socworker_id 
    LEFT JOIN 
     /* Table contains name of the certain honour_id */ 
     agency_socworker_honourtype AS asht 
      ON ash.honour_name_id = asht.id 
    LEFT JOIN 
     /* Table contains education data */ 
     agency_socworker_base_edu AS asbe 
     ON asbe.socworker_id = asw.id 
GROUP BY 
    asw.surname, 
    asw.firstname, 
    asw.fathername, 
    asw.birthday 
ORDER BY 
    asw.surname ASC 

그러나 "array_agg"기능이 아닌 필드에는 "GROUP BY"문이 필요합니다. 전체 SQL 쿼리에는 24 개의 조인 된 테이블이 있으므로

GROUP BY 
    asw.surname, 
    asw.firstname, 
    asw.fathername, 
    asw.birthday, 
    ag.shortname, 
    agr.shortname, 
    agr.fullname, 
    agdis.shortname, 
    agdis.fullname, 
    aorg.name, 
    agc.name, 
    agc.atype, 
    asnji.id, 
    asnji.new_job_contract_date, 
    assp.struct_name, 
    agdep.number, 
    agdep_type.name, 
    agdep_type.dtype, 
    aswl.work_length_checkdate, 
    aswl.work_length_protection_length_years, 
    aswl.work_length_protection_length_days, 
    aswl.work_length_protection_length_months 

쿼리가 느려집니다. "그룹화 기준"을 사용하면 처음 100 개의 데이터 행을 가져 오는 데 2 ​​초가 걸립니다. "array_agg"및 "group by"문이 없으면 250ms가 걸리지 만 페이지 매김이 있어야합니다. 얼마나 많은 데이터 행이 나에게 100 개의 고유 한 행을 가져올 지 모르기 때문에 페이지 매김을 할 수 없습니다.

답변

0

여러분이 할 수있는 최선의 방법은 사전 집계하고 다시 결합하는 것입니다. 성능에 미치는 영향에 대해서는 확신 할 수 없지만 표현식에 의한 그룹은 훨씬 적습니다. 다른 테이블과 동일한 기술 사용

with asw_agg as (
    select 
     asw.id, 
     array_agg(asbe.institue_title) as institute_title, 
     array_agg(asht.honour_type) as honour_type 
    from 
     agency_socworker asw 
     left join 
     agency_socworkerhonours ash on asw.id = ash.socworker_id 
     left join 
     agency_socworker_honourtype asht on ash.honour_name_id = asht.id 
     left join 
     agency_socworker_base_edu asbe on asbe.socworker_id = asw.id 
    group by asw.id 
) 
select 
    asw.surname, 
    asw.firstname, 
    asw.fathername, 
    asw.birthday, 
    asw_agg.honour_type, 
    asw_agg.institute_title 
from 
    asw 
    inner join 
    asw_agg using (id) 
order by asw.surname asc 
+0

감사합니다. 나는 시도 할 것이다. 나는 네가 옳다고 생각한다. 최선의 해결책이다. 나는 당신이 대답하도록 투표하고 싶지만, 나는 할 수 없다 :( – user2455668

관련 문제