2016-10-16 2 views
1

EDIT: К последнему праву для текущего состояния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   | 

и другой locations_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, ветер ..) ближайшей точку, где эти пары не нуль, а не 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) 

, который довольно быстро ~ 150мс и только индекс getti нг используется 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 не используется, если в предложении «n.station_id IN» содержится более 5 значений?

  • Есть ли способ выбрать все необходимые значения в одном запросе в разумные сроки?

Спасибо за чтение :)

PS: Postgres 9.5 с PostGIS включен

EDIT: на самом деле КТР должен выглядеть так, чтобы получить правильную точку для заказа ..но то, что сторона здесь

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 
    ) 

EDIT: После 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 

который быстро ~ 200мс даже с большим количеством станций =>https://explain.depesz.com/s/kA8

Отметьте это сообщение как ответ в течение нескольких дней.

Оптимизация по-прежнему приветствуется.

+0

Примечание: определение вашей таблицы noaa не содержит столбцов 'dt' и' station_id'. Пожалуйста, добавьте определения таблицы * real * таблицы (ов) к вашему вопросу. – joop

ответ

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) атм я использую 5 запросов и отправить их сразу для получения всех необходимых данных вместе с запросом в последнем отредактированном времени запроса.

Для запроса:

Ключ был ранжировать станции в КТР, а затем присоединиться к КТР. Этот способ сортировки выполняется намного быстрее.

Смежные вопросы