Mam tabelę PostgreSQL 9.1 z setkami tysięcy PUNKTÓW PostGIS. Dla każdego z nich chciałbym znaleźć najbliższy punkt w innej tabeli PUNKTÓW. Punkty w drugiej tabeli reprezentują siatkę na całym świecie, więc wiem, że zawsze będzie dopasowanie w zakresie 1 stopnia. To pytanie, którego używam do tej pory, które korzysta z indeksów GIST, więc jest dość szybkie (łącznie około 30 sekund).
SELECT DISTINCT ON (p.id)
p.id, ST_AsText(p.pos)
, ST_AsText(first_value(g.location) OVER (PARTITION BY p.id ORDER BY ST_Distance(p.pos, g.location::geography)))
FROM point p
JOIN grid g ON ST_DWithin(p.pos::geometry, g.location, 1)
Jedynym problemem jest linia danych. Punkty siatki mają szerokość 180, a nie -180. W przypadku korzystania z wersji geometrii ST_Distance nie zwraca punktów po drugiej stronie linii danych. Na przykład. jeśli p.pos jest POINT(-179.88056 -16.68833)
najbliższym punktem siatki POINT(180 -16.25)
, ale powyższe zapytanie go nie zwraca. Jak najlepiej to naprawić?
Tak naprawdę nie chcę mieć dwóch współrzędnych dla jednego punktu siatki (-180 i +180). Próbowałem dodać własną funkcję, która sprawdza ten konkretny przypadek, ale wtedy zapytanie nie zwraca się w ciągu 5 minut, prawdopodobnie dlatego, że nie może już korzystać z indeksu. Próbowałem także użyć wersji geograficznej ST_DWithin i to zapytanie również nie powróciło po 5 minutach.
Odpowiedzi:
OK, w końcu wymyślę sposób na zhackowanie go, które nie tylko działa wokół problemu linii danych, ale jest również szybsze.
Byłem bardzo zaskoczony, widząc, że ta funkcja, która jest wywoływana dla każdego wiersza, jest szybsza niż oryginalna funkcja okna, ale jest - ponad 10 razy szybsza. Wydajność PostgreSQL to naprawdę czarna sztuka!
źródło