Ускорение OpenStreetMap PostGIS запросов

12

У меня есть данные OpenStreetMap для Нидерландов, загруженные в базу данных PostGIS (PostgreSQL 8.3 / PostGIS 1.3.3) с использованием схемы осмоса . Это означает, что все теги хранятся в поле hstore . В дополнение к индексу GIST, который осмос создает в поле геометрии, я создал дополнительный индекс GIST для поля тегов.

Пытаясь выполнить запрос, используя как пространственное ограничение, так и ограничение на поле тегов, я обнаружил, что это медленнее, чем хотелось бы. Запрос как этот:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

требуется 22 секунды, чтобы вернуть 78 записей.

В этой таблице около 53 миллионов записей.

Есть ли способ значительно ускорить это? Я слышал, что hstore реализован значительно лучше в PostgreSQL 9, поможет ли обновление?

mvexel
источник
Поскольку это вопрос, ориентированный на базу данных, я призываю вас задать его на dba.stackexchange.com
jcolebrand
Обновление за 2015 год - PostGIS значительно улучшила производительность с тех пор, как был задан этот вопрос, поэтому учтите это, а также обновление PostgreSQL.
Тоби Спейт

Ответы:

5

Один из методов - запросить интересующие вас теги и поместить эти записи в новую таблицу. Тогда вам нужно будет только запросить новую таблицу вместо всех 53 миллионов записей. Если вы пытаетесь обновлять базу данных, этот запрос можно запускать каждый раз, когда вы получаете новые данные из OSM.

jvangeld
источник
2
Вместо того, чтобы создавать новую таблицу, вы могли бы вместо этого создать VIEW, так как ваш «запрос» напрямую связан с исходными данными без буквального дублирования данных.
RyanKDalton
7
Представление не обязательно улучшит производительность запроса, если только оно не является материализованным или эквивалентным (см. Вопрос SO в этой теме). Я не верю, что Postgresql напрямую поддерживает материализованные представления , но их можно реализовать с помощью триггеров.
Адам Армор
2
Это обходной путь, который я сейчас использую. После обновления таблиц осмоса я заново создаю несколько таблиц, оптимизированных для запросов, которые я хочу выполнить. Я просто чувствую, что должен быть лучший путь. Меня интересует тема триггеров и то, как вы могли бы использовать их для реализации представлений материалов. @ Adam Armor, есть ли шанс, что вы могли бы рассказать об этом?
mvexel
4
@mvexel Взгляните на эту вики-статью , которая охватывает основы материализованных представлений и подробно описывает, как их реализовать в PostgreSQL.
Адам Армор
5

Вы можете попытаться создать индекс для вашего столбца hstore,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

а затем используйте ?оператор, чтобы ограничить запрос только этими строками:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));
OLT
источник
Благодарность! Я уже создал этот индекс, только я не использовал его. Это только ускоряет определенные операции. В PostgreSQL 8.3 (который я использую) это только @> и? в 9.0 это @>,?,? & и? | ,
mvexel
1
Напомним, что запрос с использованием ?оператора занял 48 секунд по сравнению с 88 секундами для моего запроса (я не знаю, как я получил 72 секунды вчера, возможно, на этот раз машина выполняла что-то сложное, пока я выполнял запросы). Так что все еще не производительность, которую я ищу, но я получил более глубокое понимание того, как индексы GIST работают со столбцами hstore. Мне все еще придется пойти с другим решением создания материализованного представления, чтобы получить желаемую производительность.
mvexel
3

Функции st_within и _st_within не известны своей скоростью. Оператор && может помочь, так как он будет проверять bbox вместо геометрии

Вы можете попробовать следующее:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

Для получения дополнительных советов по производительности проверьте: http://postgis.refractions.net/docs/ch06.html

milovanderlinden
источник
2

Проблема с вашим запросом заключается в tags->'man_made'='surveillance'предложении. Это вынуждает Postgres расширять теги hstore и не позволяет ему использовать индекс. Если переписать это с помощью @>(содержит), это позволит использовать индекс.

Поскольку вы запрашиваете прямоугольник, вы можете использовать &&вместо ST_Within. Это даст небольшой выигрыш, так как ST_Within не так сложно оценить, а ST_Within неявно выполняет &&проверку.

Дополнительным увеличением скорости было бы использование индекса GIN для тегов вместо индекса GIST. Создание индексов GIN занимает больше времени, но происходит быстрее.

Весь запрос будет

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

Если вы знаете, что будете часто запрашивать определенный тег, вы можете создать частичный индекс для него CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Это позволит условию WHERE tags->'man_made'='surveillance'использовать индекс. К сожалению, этот индекс не может помочь @>запросам, а индексы GIN или GIST не могут помочь tags->'foo'запросам, поэтому вы должны сопоставить запросы с имеющимися у вас индексами.

Пол Норман
источник
Советы по использованию tags @>hstore()значительно улучшили мой запрос, спасибо.
алфавитное представление
1

попробуйте это вместо:

ВЫБЕРИТЕ n.geom, n.tags, n.tstamp, u.name ИЗ НОДОВ КАК n ВНУТРЕННИХ ПРИСОЕДИНИТЕЛЕЙ КАК ВКЛЮЧЕНО n.user_id = u.id ГДЕ теги @> 'man_made => Наблюдение' :: hstore AND ST_Within (geom , ST_GeomFromText ('POLYGON ((4,0 52,0,5,0 52,0,5,0 53,0,4,0 53,0,4,0 52,0))', 4326));

LR1234567
источник