postgresql,获取条件为真的最近点的项目列表

时间:2016-10-16 18:46:04

标签: postgresql

编辑:跳至上次编辑当前状态

你好!

我有一张带气象站的桌子

站:

id,
point, (geometry(Point,4326))
ctry (country code)

包含天气数据的表格:

NOAA:

id                 | integer                     | not null    default    nextval('noaa_id_seq'::regclass)
usaf_wban          | text                        |
station_id         | integer                     |
usaf               | integer                     |
wban               | integer                     |
dt                 | timestamp without time zone | not null
point              | geometry(Point,4326)        |
air_temp           | double precision            |
dew_point          | double precision            |
relative_humidity  | double precision            |
sea_level_pressure | double precision            |
pressure           | double precision            |
wind               | double precision            |
cloudiness         | double precision            |
ghi                | double precision            |

和另一个location_location,我得到了点

我已经用索引进行了很多实验,noaa表上的当前索引是:

Indexes:
"noaa_pkey" PRIMARY KEY, btree (id)
"noaa_dt_trunc" btree (date_trunc('hour'::text, dt))
"noaa_point" gist (point)
"noaa_station_ids" btree (station_id)

现在我想为每个参数选择(air_temp,wind ..) 此参数不是空的最近点而不是9999

此时我使用了5个单独的查询:

 with postal_station AS (
        SELECT id as station_id, s.point FROM stations s WHERE s.ctry = 'AU'
        ORDER BY s.point <-> (
            SELECT point FROM locations_location l
            WHERE l.postal_code = '9201' AND l.country_code = 'AT'
            LIMIT 1
        )
        LIMIT 5
    )
    SELECT
        DISTINCT ON (date_trunc('hour', dt))
        date_trunc('hour', dt) as dt,
        cloudiness
    FROM
        noaa n
    WHERE
        dt BETWEEN '2010-01-01'::timestamp AND '2015-01-01'::timestamp
        AND
        NOT cloudiness = 9999
        AND
        NOT cloudiness is null
        AND
        n.station_id IN (SELECT station_id FROM postal_station)
    ORDER BY dt, point <-> ( SELECT point FROM postal_station LIMIT 1 )

非常快〜150ms,唯一使用的索引是noaa_station_ids

但是目前我将station_ids的限制增加到5:

with postal_station AS (
        SELECT id as station_id, s.point FROM stations s WHERE s.ctry = 'AU'
        ORDER BY s.point <-> (
            SELECT point FROM locations_location l
            WHERE l.postal_code = '9201' AND l.country_code = 'AT'
            LIMIT 1
        )
        LIMIT 6
    )
    SELECT
        DISTINCT ON (date_trunc('hour', dt))
        date_trunc('hour', dt) as dt,
        air_temp
    FROM
        noaa n
    WHERE
        dt BETWEEN '2010-01-01'::timestamp AND '2015-01-01'::timestamp
        AND
        NOT air_temp = 9999
        AND
        NOT air_temp is null
        AND
        n.station_id IN (SELECT station_id FROM postal_station)
    ORDER BY dt, point <-> ( SELECT point FROM postal_station LIMIT 1 )

https://explain.depesz.com/s/9n2M

索引noaa_station_ids不再使用,查询大概需要~2429ms

所以这是我的问题:

  • 为什么没有使用索引noaa_station_ids如果&#34; n.station_id IN&#34;子句包含5个以上的值?

  • 有没有办法在合理的时间内在一个查询中选择所有需要的值?

感谢您阅读:)

PS:启用了postgis的Postgres 9.5

编辑:实际上cte应该看起来像这样才能得到正确的订购点..但这是一个侧面的事情

with postal_point AS (
        SELECT point FROM locations_location l
        WHERE l.postal_code = '9201' AND l.country_code = 'AT'
        LIMIT 1
    ),
    postal_station AS (
        SELECT id as station_id, s.point FROM stations s WHERE s.ctry = 'AU'
        ORDER BY s.point <-> ( SELECT point FROM postal_point )
        LIMIT 5
    )

编辑:在freenode上的joinen #postgresql之后,RhodiumToad帮我构建了这个查询

with postal_station AS (
        select
            s1.*
        from (
            select point from locations_location l where l.postal_code = '9201' AND l.country_code = 'AT' limit 1
        ) l0,
        lateral (
            select s.id, rank() over (order by s.point <-> l0.point)
            from
            stations s
            where
            s.ctry = 'AU'
        order by s.point <-> l0.point limit 20) s1
    )
    SELECT
        DISTINCT ON (date_trunc('hour', dt))
        date_trunc('hour', dt) as dt,
        air_temp
    FROM
        noaa n
    JOIN
        postal_station p
        ON
        p.id = n.station_id
    WHERE
        dt BETWEEN '2010-01-01'::timestamp AND '2015-01-01'::timestamp
        AND
        NOT air_temp = 9999
        AND
        NOT air_temp is null
    ORDER BY dt, p.rank

哪个快〜200ms即使有更多的站=&gt; https://explain.depesz.com/s/kA8

我会在几天内将这篇文章标记为已回答。

仍然欢迎优化。

1 个答案:

答案 0 :(得分:0)

1) Why is the index noaa_station_ids not used if the "n.station_id IN" clause contains more then 5 values ?

2) Is there a way to select all needed values in one query in reasonable time ?

1)在将cpu_tuple_cost增加到0.1之后,索引也被用于更多的站点,但查询仍然越来越慢,站点数量越来越多

2)atm我使用5个查询并立即发送它们以获取所有需要的数据,以及上次编辑中的查询查询时间正常。

查询:

关键是在cte中对电台进行排名,然后加入cte。 这样排序要快得多。