2016-03-21 9 views
2

У меня возникли проблемы с созданием объединения таблиц. Запрос выполняется вечно. У меня есть открытые уличные карты велосипедных маршрутов в одном столе со всеми атрибутами.PostgreSQL - очень медленное соединение таблицы по данным OSM

Table planet_osm_line 
osm_id bigint, 
route text, 
name text, 
network text, 
osmc_color text, 
reversed text, 
state text, 
"instance:cycle" text, 
"relation:id" text, 
ref text, 
description text, 
distance text, 
tags hstore, 
way geometry(LineString,900913) 

Некоторые из линий дублированы (2 или более маршрутов на одну сторону), так что я фильтруется уникальных строк в другой таблице, и я попытался объединить их с данными из planet_osm_line:

DROP TABLE IF EXISTS public.bicycle_merge; 
CREATE TABLE public.bicycle_merge AS 

WITH singleRow as ( 
    select count(way), way 
    from planet_osm_line 
    WHERE route IN ('bicycle') 
    group by way 
    having count(way) = 1 
) 
SELECT P.* 
FROM planet_osm_line P 
JOIN singleRow S 
    ON P.way = S.way 
; 

Этот запрос бежит вечно .... Простите мой вопрос о новичке, но что я делаю неправильно?

"Nested Loop (cost=28767.43..172920474.87 rows=5892712 width=335)" 
" Join Filter: (p.way = s.way)" 
" CTE singlerow" 
" -> GroupAggregate (cost=27040.24..28767.43 rows=76764 width=218)" 
"   Filter: (count(planet_osm_line1.way) = 1)" 
"   -> Sort (cost=27040.24..27232.15 rows=76764 width=218)" 
"    Sort Key: planet_osm_line1.way" 
"    -> Seq Scan on planet_osm_line1 (cost=0.00..4543.55  rows=76764 width=218)" 

Таблица Planet_osm_line имеет около 70 000 строк. Уникальная геометрия составляет около 50.000. Этот запрос работает с небольшим набором данных, но теперь я имею дело с велосипедными маршрутами по всей стране (Польша). Заранее большое спасибо!

+0

'group by way having count (way) = 1' практически ничего не делает, вы можете« выбрать отличный путь от planet_osm_line'. Но это не требует использования CTE, который действует как барьер оптимизации, поэтому вы можете просто использовать 'SELECT DISTINCT ON (путь) * FROM planet_osm_line WHERE route = 'bicycle' ORDER BY way'. – pozs

+0

Это действительно работает, но также перечисляет строки с дубликатами. Я хочу этого избежать. Мне нужны строки, которые существуют только в таблице. – Voyteck

+0

, который определяет дубликат? 'distinct on (way)' должен удалить несколько строк с одним и тем же столбцом 'way'. Или вы хотите удалить все строки, у которых есть дубликаты (а не только все, кроме одного)? – pozs

ответ

6

Вы присоединяетесь к двум простым геометриям. Это означает, что вы делаете двоичное сравнение геометрий, байта для байта между всеми возможными совпадениями. Это займет очень много времени. В вашем EXPLAIN ANALYZE стоимость CTE составляет 28 767; соединение составляет фактор 6 000 больше.

Вместо этого, вы должны проверить, если две геометрии соприкасаются друг с другом (так как OSM правильно геокодированные можно предположить, что нет пересечения линий):

WITH singleRow AS ( 
    SELECT count(way), way 
    FROM planet_osm_line 
    WHERE route IN ('bicycle') 
    GROUP BY way 
    HAVING count(way) = 1 
) 
SELECT P.* 
FROM planet_osm_line P 
JOIN singleRow S ON ST_Contains(P.way, S.way);

На множестве строк вы извлекаете, как это вы можете затем примените функцию ST_MakeLine(), чтобы фактически объединить меньшие строки в один.

+1

Отличный ответ. Я фактически изменил ST_Touches на ST_Contains, и он отлично работает. ST_Touches не работает должным образом, но спасибо в любом случае :) – Voyteck

+0

Нечетный, что ST-Touches() не будет работать. – Patrick

+0

Мой запрос занял 14 секунд. Это очень приемлемо. Еще раз спасибо! – Voyteck