Простой SQL-запрос, который фильтрует по географическому расстоянию, очень медленный - PullRequest
0 голосов
/ 04 ноября 2019

Вот мой запрос:

SELECT 1 
FROM post po
WHERE ST_DWithin(po.geog, (SELECT geog FROM person WHERE person.person_id = $1), 20000 * 1609.34, false)
ORDER BY post_id DESC
LIMIT 5;

А вот EXPLAIN ANALYZE:

enter image description here

У меня есть индекс на все, поэтому я не уверен, почему это медленно. Первые 5 сообщений при сортировке по post_id DESC удовлетворяют условию, поэтому разве это не должно возвращаться мгновенно?

Я заметил, что если я заменю вызов ST_DWithin на вызов ST_Distance, он запускается мгновенно, например так:

SELECT 1 
FROM post po
WHERE ST_Distance(po.geog, (SELECT geog FROM person WHERE person.person_id = $1)) < 20000 * 1609.34
ORDER BY post_id DESC
LIMIT 5;

Этот работает за .15 миллисекунд. Итак, простое решение состоит в том, чтобы просто заменить вызов ST_DWithin на вызов ST_Distance, нет?

Ну, к сожалению, нет, потому что не всегда совпадают первые 5 строк. Иногда он должен сканировать глубоко внутри таблицы, поэтому в этот момент ST_DWithin лучше, потому что он может использовать географический индекс, а ST_Distance не может.

Я думаю, что это может быть проблемой путаницы в планировщике запросов postgres? Мол, по какой-то причине он думает, что ему нужно выполнить сканирование всей таблицы, несмотря на то, что предложение ORDER BY x LIMIT 5 находится спереди и по центру? Не уверен ..

Ответы [ 2 ]

3 голосов
/ 05 ноября 2019

Используемое вами расстояние - почти длина экватора, поэтому вы можете ожидать (почти) всех ваших результатов, чтобы удовлетворить этому условию.

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

При использовании st_distance невозможно использовать пространственный индекс, и планировщик выберет другой план, вероятно, один полагаясьпо индексу на post_id, который пылает быстро. Но когда количество возвращаемых строк (limit) увеличивается, используется другой план, и планировщик, вероятно, полагает, что будет еще быстрее вычислить расстояние по всем строкам.

1 голос
/ 04 ноября 2019

Первые 5 сообщений при сортировке по post_id DESC удовлетворяют условию, поэтому разве это не должно возвращаться мгновенно?

Это факт, что система не может знать заранее,Он не может использовать неизвестные факты при планировании запроса. Он думает, что найдет только 10 строк. Это означает, что он думает, что должен будет отсканировать половину индекса на post_id перед накоплением 5 строк (из 10), которые соответствуют условию геометрии.

На самом деле он находит 100 000 строк (странно круглое число). Но он не узнает об этом до тех пор, пока не станет фактом.

Если вам нужно было сначала выполнить запрос на SELECT geog FROM person WHERE person.person_id = $1, а затем записать результат этого непосредственно в ваш основной запрос, а не как подзапрос, онможет (или не может) лучше планировать.

...