Очень большое количество операторов SQL UNION SELECT превышает max_stack_depth - PullRequest
0 голосов
/ 05 января 2019

Я пытаюсь разработать пространственный SQL-запрос для всех уникальных точек в одном или нескольких заданных наборах полигонов. Я использую PostGIS на облачном VPS с 6 vCPU и 16 ГБ оперативной памяти. Рассматриваемый пространственный тест - ST_Contains в предложении WHERE. Набор полигонов - это приблизительно 40 000 уникальных геометрий, которые ограничивают набор данных точечных объектов 3,7 миллиона.

Моя проблема в том, что когда я создаю запрос с более чем 13 000 полигонов (а значит, 13 000 операторов SELECT), сервер PostGIS отвечает ERROR: stack depth limit exceeded" HINT: Increase the configuration parameter "max_stack_depth".

Я хочу знать, почему и если у меня есть варианты обойти это.

Это часть упражнения по оптимизации. Я уже извлекаю геометрию многоугольника в виде отдельного SELECT для формирования требуемого SQL-запроса. Я хочу выполнить запрос, который проверяет набор многоугольников как один оператор SQL. До сих пор я строил подзапрос SELECT для каждого многоугольника, а затем UNION каждый вместе в качестве отправной точки. При компиляции запрос, использующий только 13 000 полигонов, составляет ~ 28 000 000 символов, что, на мой взгляд, намного меньше, чем предел оператора PostGIS SQL.

Я пробовал меньшие размеры и обнаружил, что есть нормальная производительность вплоть до приблизительного предела. Я достиг этого предела ранее, но, посоветовавшись с сообщением об ошибке, увеличил max_stack_depth приблизительно до размера, который возвращает ulimit -s. Насколько я понимаю, этот оператор SQL не является какой-либо рекурсивной функцией, которая, как я ожидаю, приведет к превышению глубины стека.

Также из моего чтения стека и памяти кучи я не могу понять, почему этот запрос перегружает стек, так как большая часть требуемых хранимых данных должна оказаться в куче. Я также ожидаю, что запрос будет выполняться последовательно при сборе результатов, но похоже, что PostGIS может сначала запустить все подстанции SELECT, а затем подсчитать результаты.

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

Мой текущий рабочий SQL-скрипт следует шаблону (обрезан для соответствия этому посту):

SELECT * FROM point_table WHERE ST_Contains("poly1_geom_str", pt_geom_col)
UNION
SELECT * FROM point_table WHERE ST_Contains("poly2_geom_str", pt_geom_col)
UNION
....
SELECT * FROM point_table WHERE ST_Contains("polyN_geom_str", pt_geom_col);

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

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Рассматривали ли вы or?

SELECT *
FROM point_table
WHERE ST_Contains("poly1_geom_str", pt_geom_col) OR
      ST_Contains("poly2_geom_str", pt_geom_col) OR
      ....
      ST_Contains("polyN_geom_str", pt_geom_col);
0 голосов
/ 05 января 2019

Вы можете попробовать этот вариант вашего запроса. Он создает временную таблицу из разных строк многоугольника, а затем выполняет объединение на основе ST_Contains:

SELECT  DISTINCT point_table.* 
FROM    point_table 
JOIN    (values ("poly1_geom_str"), 
                ("poly2_geom_str")
        ) as polys(poly_str)
     ON ST_Contains(poly_str, pt_geom_col)

Конечно, если эти геометрические фигуры на самом деле взяты из существующей таблицы, просто присоединитесь к этой таблице:

SELECT  DISTINCT point_table.* 
FROM    point_table 
JOIN    polys
     ON ST_Contains(poly_str, pt_geom_col)
...