Postgis ST_Intersects между двумя таблицами очень (очень) медленно - PullRequest
0 голосов
/ 01 июля 2019

Я пытаюсь сделать пространственное соединение между двумя таблицами:

  1. Таблица 1: особенности 397265 (с индексом гистограммы в поле geom)
  2. Таблица 2: 73 объекта (с основным индексом для поля geom)

Таблицы 1 и 2 имеют одинаковый SRID.

Я провел много тестов, и пространственное соединение между этими таблицами занимает несколько дней (через 5 дней я убил запрос). Я пытался понять, почему это так медленно с объяснением анализа:

EXPLAIN ANALYZE 
SELECT 
    table1.id,  table2.id
FROM table1
INNER JOIN table2 ON ST_Intersects(
        ST_Buffer(table1.geom,0),
        ST_Buffer(table2.geom,0)
)

Но пока я все еще жду результата, поскольку EXPLAIN ANALYZE действительно выполняет запрос.

Если я сделаю только ОБЪЯСНЕНИЕ, вот результат:

"Gather  (cost=1000.00..3820127.08 rows=9667 width=40)"
"  Workers Planned: 3"
"  ->  Nested Loop  (cost=0.00..3818111.26 rows=3118 width=40)"
"        Join Filter: ((st_buffer(table2.geom, '0'::double precision) && st_buffer(table1.geom, '0'::double precision)) AND _st_intersects(st_buffer(table2.geom, '0'::double precision), st_buffer(table1.geom, '0'::double precision)))"
"        ->  Parallel Seq Scan on table1  (cost=0.00..21964.50 rows=128150 width=344)"
"        ->  Seq Scan on table2  (cost=0.00..9.73 rows=73 width=714516)"

Я также обновил свой файл конфигурации postgresql относительно конфигурации моего компьютера:

shared_buffers = 8GB
effective_cache_size = 24GB
maintenance_work_mem = 2GB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 4
effective_io_concurrency = 2
work_mem = 10485kB
min_wal_size = 1GB
max_wal_size = 2GB
max_worker_processes = 7
max_parallel_workers_per_gather = 4
max_parallel_workers = 7

Не могли бы вы сказать мне, что это так долго?

Ответы [ 3 ]

3 голосов
/ 02 июля 2019

Пространственные индексы не используются.

Вы можете отказаться от вещи buffer (возможно, сначала исправить геометрию ..)

INNER JOIN table2 ON ST_Intersects(table1.geom,table2.geom)

или вы можете создавать индексы для буферизованных геометрий

CREATE INDEX geom_idx ON table1 USING gist (ST_Buffer(table1.geom,0));
1 голос
/ 03 июля 2019

Как следует из другого комментария, лучше исправить геометрию. Я предполагаю, что вы используете буфер с нулевым расстоянием для восстановления неверных геометрий. Итак, что лучше сделать, это

UPDATE table1 SET geom = st_buffer(geom,0);
UPDATE table2 SET geom = st_buffer(geom,0);

затем переиндексировать таблицу (перестроить ее исходный индекс по геометрии)

Кроме того, в зависимости от характера геометрии индекс может быть неэффективным. Сам индекс в основном представляет собой набор ограничивающих рамок для каждой геометрии (прямоугольники вокруг многоугольных или линейных фигур), и гораздо быстрее определить, какие прямоугольники сначала пересекаются, а затем из пар определить точные пересечения геометрии. Однако, если у вас слишком большие многоугольники, где большинство прямоугольников пересекаются и / или слишком сложные фигуры, это может замедлить соединение.

Кроме того, у вас могут быть данные, которые являются тяжелыми с точки зрения плотности точек, что также замедляет алгоритмы и может быть удалено без значительного ущерба для результата, особенно если эти данные не очень пространственно точны. Вы можете попытаться упростить ваши данные, например

ALTER table1 ADD COLUMN geom_simplified geom(<your geom type and srid>);
UPDATE table1 SET geom_simplified = st_snaptogrid(geom,<relevant rounding number depending on your srid and desired accuracy>);

проверить это из

0 голосов
/ 03 июля 2019

Спасибо @jgh за ответ, вы нашли проблему. Индекс не использовался. Я бы никогда не нашел его, так как для меня было очевидно, что даже с буфером индекс использовался.

Я пытался очистить данные, но есть много ошибок. Поэтому я решил использовать ваше решение (индекс ST_Buffer ())

Мой запрос занимает 14 часов. Количество функций в таблице 2 еще много времени, но, по крайней мере, запрос заканчивается ...

"Gather  (cost=1000.14..116847.28 rows=397265 width=8) (actual time=70.548..51214359.966 rows=415151 loops=1)"
"  Workers Planned: 3"
"  Workers Launched: 3"
"  ->  Nested Loop Left Join  (cost=0.14..76120.78 rows=128150 width=8) (actual time=1312.989..51210248.284 rows=103788 loops=4)"
"        ->  Parallel Seq Scan on table1  (cost=0.00..21964.50 rows=128150 width=338) (actual time=0.009..3485.290 rows=99316 loops=4)"
"        ->  Index Scan using table2_idx_buffer on table2  (cost=0.14..0.41 rows=1 width=714516) (actual time=460.535..515.510 rows=0 loops=397265)"
"              Index Cond: (st_buffer(table1.geom, '0'::double precision) && st_buffer(geom, '0'::double precision))"
"              Filter: _st_intersects(st_buffer(table1.geom, '0'::double precision), st_buffer(geom, '0'::double precision))"
"              Rows Removed by Filter: 3"
"Planning time: 0.227 ms"
"Execution time: 51214434.490 ms"
...