Прискорення запитів на 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, чи допоможе оновлення?


Оскільки це, мабуть, є питанням, орієнтованим на базу даних, рекомендую задати питання на dba.stackexchange.com
jcolebrand

Оновлення за 2015 рік - PostGIS зробив значні покращення продуктивності, оскільки було задано це питання, тому врахуйте це, а також оновлення PostgreSQL.
Toby Speight

Відповіді:


5

Одним із методів може бути запит на теги, які вас цікавлять, та розміщення цих записів у новій таблиці. Тоді вам потрібно буде лише запитувати нову таблицю замість усіх 53 мільйонів записів. Якщо ви намагаєтесь оновлювати свою базу даних, ви можете запускати цей запит щоразу, коли ви отримуєте нові дані від OSM.


2
Замість того, щоб створювати нову таблицю, ви можете замість цього створити VIEW, таким чином ви "запитуєте", пов'язані в реальному часі з вашими вихідними вихідними даними без буквального дублювання даних.
RyanKDalton

7
Перегляд не обов’язково покращить ефективність запитів, якщо тільки це не є матеріалізованим поданням або еквівалентом (див. Питання ТА на цю тему). Я не вірю, що Postgresql безпосередньо підтримує матеріалізовані погляди , але їх можна реалізувати за допомогою тригерів.
Адам Броня

2
Це вирішення, яким я зараз користуюся. Після оновлення до таблиць осмосу я знову створюю кілька таблиць, оптимізованих для запитів, які я хочу запустити. Я просто відчуваю, що має бути кращий спосіб. Тема тригерів мене заінтригує, і як ти можеш використовувати їх для реалізації матеріальних поглядів. @Adam Armor, будь-який шанс, що ти можеш поділитися цим розумінням?
mvexel

4
@mvexel Погляньте на цю статтю у wiki , яка висвітлює основи матеріалізованих поглядів та детальну інформацію про те, як їх реалізувати в PostgreSQL.
Адам Броня

5

Ви можете спробувати створити індекс для стовпця "Зберігати",

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));

Дякую! Я вже створив цей індекс, тільки не використовував його. Це лише прискорює певні операції. У 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


2

Проблема з вашим запитом - це tags->'man_made'='surveillance'пункт. Це змушує Postgres розширювати сховище тегів і не дозволяє йому використовувати індекс. Якщо ви перезаписуєте це за допомогою @>(містить), це дозволить використовувати індекс.

Оскільки ви &&запитуєте прямокутник, ви можете використовувати замість 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()масового вдосконалення мого запиту, дякую.
alphabetasoup

1

спробуйте це замість цього:

ВИБІР n.geom, n.tags, n.tstamp, u.name ІЗ вузлів ЯК ВНУТРІШНЯ ПРИЄДНАЙТЕСЬ користувачів як у ON n.user_id = u.id WHERE теги @> '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));

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.