Комбинированный ключ / значение Hstore и пространственный запрос слишком медленны для обработки больших экстрактов OSM

13

Я пытаюсь вычислить статистику для данных OSM, используя PostgreSQL 9.3.5 и PostGIS 2.1.4. Я начал с небольшого экстракта баварии, который я скачал с Geofabrik. Схема db - это обычная схема API 0.6, данные были импортированы с помощью метода дампа в Postgres (с использованием сценариев pgsnapshot_schema_0.6 * .sql, которые поставляются с осмосом). АНАЛИЗ ВАКУУМА также был выполнен.

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

Я сейчас пытаюсь добиться подсчета всех узлов, которые находятся внутри границ admin = 6 Баварии. Вот мой SQL-запрос:

SELECT relpoly.id, count(node) 
FROM bavaria.relpolygons relpoly, bavaria.nodes node
WHERE relpoly.tags @> '"boundary"=>"administrative","admin_level"=>"6"'::hstore 
AND ST_Intersects(relpoly.geom, node.geom)
GROUP BY relpoly.id;

Время выполнения этого запроса ужасно, потому что Postgres выполняет соединение с вложенным циклом и просматривает все узлы для каждой границы admin = 6. К вашему сведению, Бавария разделена на 98 admin = 6 полигонов, и в экстракте Баварии находится около 30 миллионов узлов.

Можно ли избежать этого неоптимального выполнения запроса и сказать Postgres, что он должен сканировать все узлы только один раз (например, путем увеличения счетчика для соответствующего многоугольника в наборе результатов или с помощью подсказок)?

Редактировать:

1) пространственный индекс существует на узлах Баварии:

CREATE INDEX idx_nodes_geom ON bavaria.nodes USING gist (geom);

2) план запроса выглядит так:

HashAggregate  (cost=284908.49..284908.75 rows=26 width=103)
  ->  Nested Loop  (cost=111.27..283900.80 rows=201537 width=103)
        ->  Bitmap Heap Scan on relpolygons relpoly  (cost=4.48..102.29 rows=26 width=5886)
              Recheck Cond: (tags @> '"boundary"=>"administrative", "admin_level"=>"6"'::hstore)
              ->  Bitmap Index Scan on relpolygons_geom_tags  (cost=0.00..4.47 rows=26 width=0)
                    Index Cond: (tags @> '"boundary"=>"administrative", "admin_level"=>"6"'::hstore)
        ->  Bitmap Heap Scan on nodes node  (cost=106.79..10905.50 rows=983 width=127)
              Recheck Cond: (relpoly.geom && geom)
              Filter: _st_intersects(relpoly.geom, geom)
              ->  Bitmap Index Scan on idx_nodes_geom  (cost=0.00..106.55 rows=2950 width=0)
                    Index Cond: (relpoly.geom && geom)

3)

Я создал следующие два индекса, но план запроса (и время выполнения) не изменился

CREATE INDEX relpolygons_tags_boundary on bavaria.relpolygons( (tags->'boundary') );
CREATE INDEX relpolygons_tags_admin on bavaria.relpolygons( (tags->'admin_level') );
ANALYZE bavaria.relpolygons;
Альф Кортиг
источник
1
У вас есть пространственный индекс в bavaria.nodes?
user30184
да, я отредактировал вопрос и предоставил информацию об индексе узлов и плане запросов
Альф Кортиг,
3
Два варианта. 1 - добавить индекс для тегов hstore. 2 - извлеките теги, которые вы используете для запроса ( boundaryи admin_level), в дополнительные столбцы таблицы и используйте их напрямую.
BradHards
См. Edit (3): два индекса были добавлены, но не было никаких изменений ни в плане запроса, ни во время выполнения.
Альф Кортиг
После некоторого тестирования я больше не уверен, создал ли я правильные индексы в (3). Пока мне удалось создать индекс для -> и? Операторы магазина. Тем не менее, я использую @> в своем запросе
Alf Kortig

Ответы:

5

Лучший способ индексировать теги hstore - использовать индексы GIN или GIST, которые из документов поддерживают @>,?,? & И? | операторы , то есть поиск по ключам и парам ключ / значение. Вы подходите к использованию функции для извлечения тегов для индекса B-дерева разумно, но поскольку вы также проверяете конкретные пары ключ / значение, анализатор выбрал полное сканирование таблицы.

У меня нет доступа к bavaria.relpolygons, но на основе аналогичного запроса для OSM UK по ограничениям скорости и тегам шоссе я получу это для своего объяснения по следующему запросу:

SELECT count(*) 
 FROM ways 
WHERE tags @> 'highway=>motorway'::hstore 
 AND tags @> 'maxspeed=>"50 mph"'::hstore;


Aggregate  (cost=48.66..48.67 rows=1 width=0)
    ->  Index Scan using ix_ways_tags_gist on ways  (cost=0.42..48.64 rows=11 width=0)
     Index Cond: ((tags @> '"highway"=>"motorway"'::hstore) AND (tags @> '"maxspeed"=>"50 mph"'::hstore))

который показывает прямое сканирование индекса (с использованием индекса gist), что для таблицы с 10 миллионами строк обнадеживает. Индекс был создан с простым:

CREATE INDEX ix_ways_tags_gist ON ways USING gist (tags);

Хотя я не могу проверить ваше пространственное состояние, я предполагаю, что оно менее избирательно, чем

ГДЕ relpoly.tags @> '"border" => "административный", "admin_level" => "6"' :: hstore.

и поэтому будет использоваться только для условия перепроверки.

Существует также отличный ответ SO на разницу между индексами GIN и GIST . Общий вывод заключается в том, что индексы GIN, хотя они больше и медленнее создаются, намного быстрее справляются с проблемами поиска текста.

Извините, что отвечаю так поздно, но недавно я выполнял аналогичную работу над OSM и hstore, и обнаружил, что я не только однажды поставил этот вопрос, но и теперь могу ответить на него: D.

Джон Пауэлл
источник