如何在Postgres中缩短或优化JOIN查询

时间:2020-02-29 08:10:11

标签: postgresql

我得到以下查询,我参加了4次。但是返回结果要花费很多时间。 有什么方法可以优化此查询?

    SELECT T1.wbd_date as WBD_DATE,  to_char(T1.wbd_block_no, 'fm00') as BLOCK_NO, T2.wbd_value as AmbHum, T3.wbd_value as AmbTemp,
T4.wbd_value as SWT, T5.wbd_value as Expval
FROM (
SELECT wbd_attribute_id, wbd_date, wbd_block_no, wbd_value 
FROM wb_block_data ) T1 
JOIN wb_block_data T2 on T1.wbd_date = T2.wbd_date AND T1.wbd_block_no = T2.wbd_block_no and T2.wbd_attribute_id = 152112 and to_char(T2.wbd_date,'MM YYYY')='07 2019'
JOIN wb_block_data T3 on T1.wbd_date = T3.wbd_date AND T1.wbd_block_no = T3.wbd_block_no and T3.wbd_attribute_id = 152116 and to_char(T3.wbd_date,'MM YYYY')='07 2019'
JOIN wb_block_data T4 on T1.wbd_date = T4.wbd_date AND T1.wbd_block_no = T4.wbd_block_no and T4.wbd_attribute_id = 152120 and to_char(T4.wbd_date,'MM YYYY')='07 2019'
JOIN wb_block_data T5 on T1.wbd_date = T5.wbd_date AND T1.wbd_block_no = T5.wbd_block_no and T5.wbd_attribute_id = 150661 and to_char(T5.wbd_date,'MM YYYY')='07 2019'

3 个答案:

答案 0 :(得分:1)

您实质上是在做枢轴操作,使用条件聚合可能会更快:

select wbd_attribute_id, block_no, wbd_date,
       max(wbd_value) filter (where wbd_attribute_id = 152112) as AmbHum,
       max(wbd_value) filter (where wbd_attribute_id = 152116) as AmbTemp,
       max(wbd_value) filter (where wbd_attribute_id = 152120) as swt,
       max(wbd_value) filter (where wbd_attribute_id = 152120) as Expval
from (
  SELECT wbd_attribute_id, wbd_date, to_char(wbd_block_no, 'fm00') as block_no, wbd_value 
  FROM wb_block_data 
  where wbd_attribute_id in (152112, 152116, 152120, 150661)
    and wbd_date >= DATE '2019-07-01' 
    and wbd_date < DATE '2019-08-01'
) t
group by wbd_attribute_id, wbd_date, block_no

您想要为此在(wbd_attribute_id, wbd_date)上建立索引。

答案 1 :(得分:0)

如下所示的索引可能会起作用:

CREATE INDEX idx ON wb_block_data (wbd_date, wbd_block_no, wbd_attribute_id);

但是,我们还需要使连接条件具有可控性:

SELECT T1.wbd_date as WBD_DATE, to_char(T1.wbd_block_no, 'fm00') as BLOCK_NO, T2.wbd_value as AmbHum, T3.wbd_value as AmbTemp, T4.wbd_value as SWT, T5.wbd_value as Expval
FROM
(
    SELECT wbd_attribute_id, wbd_date, wbd_block_no, wbd_value 
    FROM wb_block_data
) T1 
JOIN wb_block_data T2 on T1.wbd_date = T2.wbd_date AND T1.wbd_block_no = T2.wbd_block_no and T2.wbd_attribute_id = 152112 and T2.wbd_date >= '2019-07-01' and T2.wbd_date < '2019-08-01'
JOIN wb_block_data T3 on T1.wbd_date = T3.wbd_date AND T1.wbd_block_no = T3.wbd_block_no and T3.wbd_attribute_id = 152116 and T3.wbd_date >= '2019-07-01' and T3.wbd_date < '2019-08-01'
JOIN wb_block_data T4 on T1.wbd_date = T4.wbd_date AND T1.wbd_block_no = T4.wbd_block_no and T4.wbd_attribute_id = 152120 and T4.wbd_date >= '2019-07-01' and T4.wbd_date < '2019-08-01'
JOIN wb_block_data T5 on T1.wbd_date = T5.wbd_date AND T1.wbd_block_no = T5.wbd_block_no and T5.wbd_attribute_id = 150661 and T5.wbd_date >= '2019-07-01' and T5.wbd_date < '2019-08-01';

我对查询所做的唯一更改是将日期要求表达为一个范围,而没有使用to_char

wbd_date >= '2019-07-01' and wbd_date < '2019-08-01'

这是可修改的,这意味着Postgres也许可以使用wbd_date列上的索引来满足2019年7月的日期范围。

答案 2 :(得分:0)

我将查询更改为此,并因此迅速获得所需的结果

SELECT T1.wbd_date as WBD_DATE,  to_char(T1.wbd_block_no, 'fm00') as BLOCK_NO, T2.wbd_value as AmbHum, T3.wbd_value as AmbTemp,
T4.wbd_value as SWT, T5.wbd_value as Expval
FROM (
SELECT wbd_attribute_id, wbd_date, wbd_block_no, wbd_value 
FROM wb_block_data where to_char(wbd_date,'MM YYYY')='07 2019') T1 
JOIN wb_block_data T2 on T1.wbd_date = T2.wbd_date AND T1.wbd_block_no = T2.wbd_block_no and T2.wbd_attribute_id = 152112 
JOIN wb_block_data T3 on T1.wbd_date = T3.wbd_date AND T1.wbd_block_no = T3.wbd_block_no and T3.wbd_attribute_id = 152116 
JOIN wb_block_data T4 on T1.wbd_date = T4.wbd_date AND T1.wbd_block_no = T4.wbd_block_no and T4.wbd_attribute_id = 152120 
JOIN wb_block_data T5 on T1.wbd_date = T5.wbd_date AND T1.wbd_block_no = T5.wbd_block_no and T5.wbd_attribute_id = 150661