Як виправити проблему з продуктивністю в PostGIS ST_Intersects?


9

Я новачок у поштовій службі, і у мене є проблеми з виконанням запитів.

Це мій запит:

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes here',4326),position) 
ORDER BY userid, timestamp desc

і проблема полягає в тому, що мій багатокутник включає ДУЖЕ великі багатокутники (довжиною 600 сторінок у слові doc!), а на його виконання пішло більше 2 годин!

Чи є спосіб оптимізувати запит або скористатися іншим способом?

Будь ласка, ваша допомога дуже вдячна!

Відповіді:


8

Що ви повинні зробити, це помістити ваш великий багатокутник у таблицю як одиничні багатокутники (з ST_Dump) і поставити на нього індекс. Щось на зразок:

CREATE TABLE big_polygon as
SELECT (ST_Dump( ST_GeomFromText('a multiypolygon geom goes here',4326))).geom as geom;

-- It is always great to put a primary key on the table
ALTER table big_polygon ADD Column gid serial PRIMARY KEY;

-- Create the index
CREATE INDEX idx_big_polygon_geom
on big_polygon
USING gist(geom);

-- To give the database some information about how the index looks
analyze big_polygon;

-- Then you go:
SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1, big polygon WHERE ST_Intersects ( big_polygon.geom,position) 
ORDER BY userid, timestamp desc;

Це повинно бути швидше з кількох причин.


Дякую Нікласу за цю чудову відповідь. Вибачте, я пропустив зазначити, що у мене є більше полігонів, і вони вже зберігаються в таблиці з індексом. Але я хотів би, щоб дані геомашини безпосередньо були швидшими. Однак я намагаюся так, як ви запропонуєте, але це все ще займе дуже багато часу! будь-які інші пропозиції?
Сара

@Sara. Гаразд, значить, ви намагалися розділити багатогеоелектрики на єдині геометрії, як я пропоную з ST_Dump?
Nicklas Avén

Про скільки позицій користувачів ми говоримо? Скільки великих багатокутників? Що ви отримуєте від SELECT ST_npoints (geom) від big_polygons_table ;?
Nicklas Avén

Вибачте, моє погано, дозвольте мені пояснити більше про мої таблиці, щоб зробити вас більш зрозумілим: у мене є таблиця1, яка містить стовпчик геомасив, який має близько 230 рядків, і в кожному ряду є багатополігон (вони представляють країни, тому вони різняться за розміром) , і мають індекс у колу__гему. Таблиця2, що включає стовпець позиції (точки), часову позначку, userid та id (pk) та 3 індекси, створені за допомогою (позиція, часова марка, userid). Ця таблиця дуже велика, приблизно 103496003 рядків. 16. Вибачте, якщо я вас збентежив, але мені дуже потрібна ваша допомога! Спасибі
Сара

2

Це залежить, яка якість - точність вам потрібна. Очевидно, ви можете спростити багатокутники, скориставшись: http://postgis.net/docs/ST_Simplify.html

Те, що я часто робив під час розробки моєї програми GIS, - це думати про найкращий спосіб мінімізувати дані. Напр. наприклад, попередньо виділіть багатокутники в прикордонному полі. - Залежно від масштабування вам не потрібні надто точні результати (st_simplify) тощо.

Сподіваюся, що вам трохи допомогло!


Дякую Мартіну за швидку відповідь. Моя проблема - мені потрібно, щоб результат був дуже точним, тому я думаю, що ця функція мені тут не допоможе! але дякую за пропозицію
Сара

0

Залежно від ваших постгрес та / або експертизи sql, у вас є кілька варіантів:

  1. проаналізуйте запит за допомогою команди EXPLAIN, щоб з’ясувати, чи потрапляєте ви у певне вузьке місце. Попередження: іноді вихід EXPLAIN може бути важким для розуміння

  2. якщо ви очікуєте, що більшість або значна частина геометрій у таблиці1 НЕ перетинаються з мультиполігоном, ви можете спробувати застосувати попередню умову до більш простого багатокутника (тобто, розбивши мультиплайгон на більш дрібні шматки), а потім запустити більш важкий перетин багатополігону лише на ці результати. Дивіться приклад нижче.

  3. якщо і тільки якщо CPU є вузьким місцем (тобто сервер застряг у перехрестях обчислень), я настійно пропоную вам отримати більший, швидший, потужніший процесор або орендувати одноразовий екземпляр високого CPU від Amazon EC2 та знищити його, коли ви зроблено

Приклад запиту для елемента 2:

SELECT DISTINCT ON (st1.userid) st1.userid ,ST_AsText(st1.position), st1.timestamp  
FROM (
    select userid, position, timestamp from table1 
    WHERE ST_Intersects ( YOUR_MULTIPOL_BOUNDS_HERE,position)
) as st1 
WHERE ST_Intersects ( ST_GeomFromText('a multiypolygon geom goes     here',4326),st1.position) 
ORDER BY st1.userid, st1.timestamp desc

Для підвищення продуктивності ви також можете тимчасово матеріалізувати підвідбір st1 у вигляді таблиці, щоб ви могли його індексувати.

@Nicklas правильно вказав у коментарях, що приклад пропозиції 2 не повинен допомогти. Він правий, але я думаю, що я (частково) також правий.

Насправді, схоже, дуже подібне запитання було задано (і відповіли) лише в листопаді минулого року на пошті ML:

http://postgis.refractions.net/pipermail/postgis-users/2011-November/031344.html

і виявляється, пропозиція полягає в тому, щоб насправді розбити багатокутник, щоб індекс міг найефективніше відфільтрувати помилкові перехрестя, які в іншому випадку будуть спровоковані простою граничною перевіркою.


пропозиція 2 не повинна допомагати, тому що саме це робить індекс. Тож ця конструкція буде робити те саме ще раз.
Nicklas Avén

@ NicklasAvén ви праві, я змінив відповідь
unicoletti

0

Використання ST_SubDivide()

Для версії 2.2 Postgis ви можете використовувати ST_SubDivide.

ST_Subdivide - Повертає набір геометрії, коли жодна геометрія у наборі не має більше зазначеної кількості вершин.

setof geometry ST_Subdivide(geometry geom, integer max_vertices=256);

Ви також можете

  • використовувати таблицю темп
  • індекс

Тут ми використовуємо ST_SubDivideдля розбиття багатокутника на підполігони з 10 або меншими вершинами.

CREATE TEMP TABLE divided AS
SELECT ST_SubDivide(bigmultipolygon,10)::geometery AS t(geom);

CREATE INDEX divided_idx ON divided USING gist(geom);

Тоді

SELECT DISTINCT ON (userid) userid ,ST_AsText(position), timestamp  
FROM table1
JOIN divided AS d
  ON ST_Intersects( d.geom, position )
ORDER BY userid, timestamp desc;

Не роби цього, це вводить помилки округлення

Загальна настройка

Також дивіться розділ підказки щодо ефективності в документах. Переконайтесь, що ви налаштовані належним чином. Подумайте про підняття, max_parallel_workers_per_gatherщоб скористатися паралелізацією (наразі за замовчуванням вимкнено).

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