Делать запрос ST_Distance масштабируемым при высоких нагрузках? - PullRequest
1 голос
/ 15 марта 2019

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

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

Select * from my_table where business_type = 'bakeries';

Это не показалось мне идеальным, так как на конце приложений было заметное отставание в полсекунды, когда он сортировал данные, чтобы найти ближайший. В настоящее время я изучаю, могут ли все вычисления выполняться быстрее в конце базы данных. Таким образом, я узнал о POSTGIS и его функциях, чтобы найти координаты, наиболее близкие к входу. Используя его функциональность, я придумал этот запрос, который будет выполняться для каждого пользовательского запроса:

SELECT *, ST_Distance(ST_GeogFromText('SRID=4326;POINT(user_long user_lat)'), geom, false) as 
distance from my_table where business_type = 'Insurance'  order by distance limit 1;

Это, кажется, намного более быстрый ответ, особенно для типов бизнеса, у которых есть много списков в таблице (таких как Страховые компании). Тем не менее, я замечаю, что он ужасно масштабируется, когда я пытаюсь провести стресс-тестирование поступающих запросов. 500 одновременных запросов к URL-адресу быстро приводят к тому, что загрузка ЦП базы данных достигает 100%, поэтому этот подход не будет работать в пиковые моменты времени.

"Limit  (cost=12804.92 rows=1 width=261)"
"  ->  Sort  (cost=12804.91..12878.92 rows=29602 width=261)"
"        Sort Key: (_st_distance('0101000020E61000007AC7293A927F52C0D34D621058614440'::geography, (geom)::geography, '0'::double precision, false))"
"        ->  Index Scan using business_name_index on my_table  (cost=0.43..12656.90 rows=29602 width=261)"
"              Index Cond: (business_type = 'Insurance'::text)"

Есть ли способ сделать это гораздо более жизнеспособным, или я должен отказаться от этой идеи и попробовать другой путь? Я знаю одну альтернативу - использовать ST_DWithin, чтобы найти все ближайшие адреса в определенном радиусе (как показано здесь ), но я не могу определить минимальное расстояние, так как некоторые могут быть слишком далеко для пользователя по умолчанию.

Ответы [ 2 ]

2 голосов
/ 18 марта 2019

Я второй ответ Евгенса, предполагая, что координаты вашего бизнеса также POINT, а не POLYGON или что-то в этом роде, что может привести к несоответствиям с расстояниями, близкими друг к другу, поскольку <-> использует ограничивающие рамки.Но ST_Distance() не использует индекс, поэтому, если производительность является главным приоритетом, это путь.

Подробнее о вашей конкретной проблеме вы можете прочитать здесь: http://postgis.net/workshops/postgis-intro/knn.html

Вам понадобится 2d индекс GiST на вашем geom -колонне, чтобы функция <-> могла использовать btw.

CREATE INDEX idx_mytable_geom ON my_table USING Gist(geom);

Также вы можете рассмотреть возможность использования ST_GeomFromText() и преобразовать ваш geom -колонку вgeometries как geometries, кажется, работает лучше, чем geographies.

Найти больше здесь: https://medium.com/coord/postgis-performance-showdown-geometry-vs-geography-ec99967da4f0

Или даже лучше использовать ST_MakePoint(), который также создает geometries и быстрее, чем ST_GeomFromtext().

Проверьте здесь:https://gis.stackexchange.com/questions/58605/which-function-for-creating-a-point-in-postgis

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

Итак, ваш код будет выглядеть так:

SELECT a.*, ST_SetSRID(ST_MakePoint(lng lat), 4326) <-> a.geom as dist
FROM my_table a
where business_type = 'Insurance'
ORDER BY dist;

Это мои идеи.

1 голос
/ 18 марта 2019

Полагаю, у вас все еще есть возможность улучшить производительность вашего приложения с помощью оператора <-> (вместо ST_Distance()), поскольку он использует пространственный индекс и позволяет даже выполнять пространственный поиск быстрее.

...