POSTGRES汇总联接表中的数据

时间:2014-07-14 08:48:29

标签: postgresql query-optimization postgresql-9.1

在POSTGRES 9.1中运行sql-query。该查询使用24个LEFT JOIN。 每个连接的表都可以有1到10-15个与上一个表相关的数据行。作为sql-query的结果,我有很多数据行,彼此相差1个值

SQL查询示例:

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

我想得到以下内容:

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

但这需要" GROUP BY"声明不在" array_agg"功能。由于完整的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

这会减慢查询速度。使用" group by"获取前100个数据行需要2秒钟。没有" array_agg" " group by"声明需要250毫秒,但我必须有分页。我不能分页,因为我不知道有多少数据行可以获得100个独特的行。

1 个答案:

答案 0 :(得分: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