PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Badanie spowolnienia PostGIS (edycja 2019)

Podobnie jak w zeszłym roku, jeden z naszych długoletnich klientów zgłosił się do nas, ponieważ jedno z ich istniejących od dawna zapytań PostgreSQL dotyczących obliczeń geometrii PostGIS było znacznie wolniejsze dla określonych wartości. Zbadaliśmy problem i dowiedzieliśmy się, jak go rozwiązać; Czytaj! To, co znaleźliśmy jako przyczynę problemu, zaskoczy Cię!

Początkową obserwacją, zgłoszoną przez naszego klienta, było uruchomienie zapytania obejmującego ST_DistanceSpheroid zajęło około 7 milisekund, gdy poproszono o zwrócenie odległości do POINT(33.681953 23.155994) na określonej sferoidzie, ale jeśli ten punkt został przeniesiony do POINT(33.681953 23.1559941) (różnica tylko 0.0000001 ) zajęło to 0,13 milisekundy. 60 razy szybciej! Co u licha (kolejna sferoida!) może się dziać?

Początkowo nie byliśmy w stanie odtworzyć spowolnienia w naszych środowiskach testowych. W naszych rękach oba zapytania wykonałyby się równie szybko, bez spowolnienia. Sięgnęliśmy do konkretnych wersji używanego oprogramowania, myśląc, że może być potrzebna aktualizacja. Wykorzystaliśmy wersje zgłoszone przez klienta:PostgreSQL 10.11, PostGIS 2.4.4, libproj 4.93. Wróciliśmy do wieków jaskiniowych, degradując je do tych dokładnych wersji, bez powodzenia.

W końcu zdaliśmy sobie sprawę, że klient używa Ubuntu 18.04, więc spróbowaliśmy tego… i oto problem się tam powtórzył. Wystarczy powiedzieć, że skorzystaliśmy z możliwości profilowania zapytania w tej maszynie. Mamy to:

Samples: 224K of event 'cpu-clock', Event count (approx.): 56043500000
  Children      Self  Command   Shared Object           Symbol
+   84.86%     0.00%  postgres  [unknown]               [.] 0xffffffffffffffff
+   84.59%     0.00%  postgres  postgres                [.] DirectFunctionCall4Coll
+   84.58%     0.00%  postgres  postgis-2.5.so          [.] geometry_distance_spheroid
+   84.56%     0.00%  postgres  liblwgeom-2.5.so.0.0.0  [.] lwgeom_distance_spheroid
+   84.31%     0.19%  postgres  libm-2.27.so            [.] __sincos
+   84.18%     0.00%  postgres  libm-2.27.so            [.] __cos_local (inlined)
+   84.13%     0.00%  postgres  libm-2.27.so            [.] cslow2 (inlined)
+   84.05%     0.01%  postgres  libm-2.27.so            [.] __mpcos
+   83.95%     0.32%  postgres  libm-2.27.so            [.] __c32
+   83.87%     0.00%  postgres  postgres                [.] ExecInterpExpr
+   83.75%     0.00%  postgres  postgres                [.] standard_ExecutorRun
+   83.75%     0.00%  postgres  postgres                [.] ExecutePlan (inlined)
+   83.73%     0.00%  postgres  postgres                [.] ExecProcNode (inlined)
+   83.73%     0.00%  postgres  postgres                [.] ExecScan
+   83.67%     0.00%  postgres  postgres                [.] ExecProject (inlined)
+   83.67%     0.00%  postgres  postgres                [.] ExecEvalExprSwitchContext (inlined)
+   83.65%     0.00%  postgres  postgres                [.] _SPI_execute_plan
+   83.60%     0.00%  postgres  postgres                [.] _SPI_pquery (inlined)
+   83.49%     0.01%  postgres  plpgsql.so              [.] exec_stmts
+   83.49%     0.00%  postgres  plpgsql.so              [.] exec_stmt (inlined)
+   83.49%     0.00%  postgres  plpgsql.so              [.] exec_stmt_fori (inlined)
+   83.48%     0.00%  postgres  plpgsql.so              [.] exec_stmt_perform (inlined)
+   83.48%     0.00%  postgres  plpgsql.so              [.] exec_run_select
+   83.47%     0.00%  postgres  postgres                [.] SPI_execute_plan_with_paramlist
+   81.67%     0.01%  postgres  liblwgeom-2.5.so.0.0.0  [.] edge_distance_to_point
+   81.67%     0.00%  postgres  liblwgeom-2.5.so.0.0.0  [.] 0x00007f2ce1c2c0e6
+   61.85%    60.82%  postgres  libm-2.27.so            [.] __mul
+   54.83%     0.01%  postgres  liblwgeom-2.5.so.0.0.0  [.] sphere_distance
+   27.14%     0.00%  postgres  plpgsql.so              [.] exec_stmt_block
+   26.67%     0.01%  postgres  liblwgeom-2.5.so.0.0.0  [.] geog2cart
+   19.24%     0.00%  postgres  libm-2.27.so            [.] ss32 (inlined)
+   18.28%     0.00%  postgres  libm-2.27.so            [.] cc32 (inlined)
+   12.55%     0.76%  postgres  libm-2.27.so            [.] __sub
+   11.46%    11.40%  postgres  libm-2.27.so            [.] sub_magnitudes
+    8.15%     4.89%  postgres  libm-2.27.so            [.] __add
+    4.94%     0.00%  postgres  libm-2.27.so            [.] add_magnitudes (inlined)
+    3.18%     3.16%  postgres  libm-2.27.so            [.] __acr
+    2.66%     0.00%  postgres  libm-2.27.so            [.] mcr (inlined)
+    1.44%     0.00%  postgres  liblwgeom-2.5.so.0.0.0  [.] lwgeom_calculate_gbox_geodetic
+    1.44%     0.00%  postgres  liblwgeom-2.5.so.0.0.0  [.] ptarray_calculate_gbox_geodetic

Mówisz, bełkot. Jest jednak coś bardzo ciekawego w tym profilu… i musisz zignorować pierwsze 26 linii i skupić się na __mul linia tam. Widzisz, że 60,82% czasu „własnego”? (Słyszę dźwięk realizacji, który właśnie stworzył twój umysł). Dlaczego więc niektóre punkty na sferoidzie zajmują tyle czasu, a inne nie? A także dlaczego w Ubuntu 18.04 trwa to długo, ale nie na innych maszynach? Dlaczego aktualizacja PostGIS nie rozwiązuje problemu?

Odpowiedź została mi zasugerowana, gdy zdałem sobie sprawę z tego, co było oczywiste:PostGIS wykonuje wiele trygonometrii (sinus, cosinus, tangens itp.), wywołując libm Funkcje. Przeglądając dzienniki zmian glibc, znaleźliśmy pewne optymalizacje w funkcjach trygonometrycznych:w przypadku niektórych danych wejściowych obliczenia trygonometryczne są wykonywane na skróty, których nie można zastosować w przypadku innych danych wejściowych; i takie skróty zostały z czasem zoptymalizowane. Rzeczywiście, glibc ogłasza dla obu wersji 2.27 i 2.29 o optymalizacji funkcji sinus/cosinus/etc. Najwyraźniej kiedyś Intel wprowadził optymalizacje, które miały zapewnić bardzo dokładne wyniki, ale ktoś zdał sobie sprawę, że twierdzenie o dokładności było nieprawidłowe, więc glibc wyłączyło korzystanie z tych optymalizacji; później te rzeczy zostały ponownie zaimplementowane w inny, ale znowu szybki sposób. Albo coś w tym rodzaju — osobom z zewnątrz, takim jak ja, trudno jest ustalić dokładne szczegóły.

Podejrzewaliśmy, że aktualizacja do nowszej wersji glibc rozwiąże problem, pozostawiając wszystko inne bez zmian. Nasz klient tego spróbował i rzeczywiście tak było i byli zadowoleni. Nie jesteśmy do końca pewni, który z tych zmian glibc były odpowiedzialne, ale jedno jest jasne:zawsze dobrym pomysłem jest uruchamianie rzeczy na aktualnym oprogramowaniu.

Pamiętaj, że krwawiące krawędzie są ostre… więc bądź ostrożny.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak wykonać tę samą agregację w każdej kolumnie, nie wymieniając kolumn?

  2. Jak zapewnić klientowi API 1 000 000 wyników z bazy danych?

  3. Postgres:WSTAW, jeśli jeszcze nie istnieje

  4. Inny db do testowania w Django?

  5. Typecast string to integer