PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Untersuchung der Langsamkeit von PostGIS (Ausgabe 2019)

Gerade als das letzte Jahr zu Ende ging, kam einer unserer langjährigen Kunden zu uns, weil eine seiner seit langem bestehenden PostgreSQL-Abfragen mit PostGIS-Geometrieberechnungen für bestimmte Werte viel langsamer war. Wir haben das Problem recherchiert und herausgefunden, wie man es löst; weiter lesen! Was wir als Ursache des Problems gefunden haben, wird Sie überraschen!

Die anfängliche Beobachtung, die von unserem Kunden gemeldet wurde, war die Ausführung einer Abfrage mit ST_DistanceSpheroid dauerte etwa 7 Millisekunden, als er aufgefordert wurde, die Entfernung zu POINT(33.681953 23.155994) zurückzugeben auf einem bestimmten Sphäroid, aber wenn dieser Punkt nach POINT(33.681953 23.1559941) verschoben wurde (ein Unterschied von nur 0.0000001 ) dann dauerte es 0,13 Millisekunden. 60 Mal schneller! Was um alles in der Welt (ein weiteres Sphäroid!) könnte hier vor sich gehen?

In unseren Testumgebungen konnten wir die Langsamkeit zunächst nicht reproduzieren. In unseren Händen würden beide Abfragen gleich schnell und ohne Verlangsamung ausgeführt. Wir haben uns mit den spezifischen Versionen der verwendeten Software beschäftigt, weil wir dachten, dass ein Update erforderlich sein könnte. Wir haben die vom Kunden gemeldeten Versionen verwendet:PostgreSQL 10.11, PostGIS 2.4.4, libproj 4.93. Wir kehrten zu den Höhlenzeitaltern zurück, indem wir ohne Erfolg auf genau diese Versionen heruntergestuft wurden.

Irgendwann wurde uns bewusst, dass der Kunde Ubuntu 18.04 verwendet, also haben wir das versucht … und siehe da, das Problem reproduzierte sich dort. Es genügt zu sagen, dass wir die Gelegenheit ergriffen haben, die Abfrage in dieser Maschine zu profilieren. Wir haben Folgendes:

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

Kauderwelsch, sagst du. Dieses Profil hat jedoch etwas sehr Merkwürdiges … und Sie müssen die ersten 26 Zeilen ignorieren und sich auf __mul konzentrieren Linie dort. Sehen Sie, dass 60,82 % der Zeit für sich selbst sind? (Ich kann den Klang der Erkenntnis hören, die dein Verstand gerade gemacht hat). Warum dauert es also für bestimmte Punkte auf dem Sphäroid so lange und für andere nicht? Und warum dauert es in Ubuntu 18.04 lange, aber nicht in anderen Maschinen? Warum behebt die Aktualisierung von PostGIS das Problem nicht?

Die Antwort wurde mir vorgeschlagen, als mir klar wurde, was offensichtlich war:PostGIS führt eine Menge Trigonometrie (Sinus, Cosinus, Tangens usw.) durch, indem es libm aufruft Funktionen. Beim Betrachten der glibc-Änderungsprotokolle haben wir einige Optimierungen in Trigonometriefunktionen gefunden:Für bestimmte Eingaben nehmen Trigonometrieberechnungen Abkürzungen, die für andere Eingaben nicht verwendet werden können; und solche Verknüpfungen wurden im Laufe der Zeit optimiert. Tatsächlich kündigt die glibc sowohl für 2.27 als auch für 2.29 an, dass beide Optimierungen in Sinus-/Cosinus-/usw.-Funktionen erwähnen. Anscheinend gab es einmal einige Optimierungen von Intel, die sehr genaue Ergebnisse liefern sollten, aber dann erkannte jemand, dass die Behauptung der Genauigkeit falsch war, also deaktivierte glibc die Verwendung dieser Optimierungen; Später wurde das Zeug auf eine andere, aber wieder schnelle Art und Weise neu implementiert. Oder so ähnlich – für Außenstehende wie mich ist es schwierig, die genauen Details herauszufinden.

Wir vermuteten, dass ein Upgrade auf eine neuere Version von glibc das Problem beheben und alles andere beim Alten lassen würde. Unser Kunde hat das versucht, und es stimmte tatsächlich, und er war glücklich. Wir sind nicht wirklich sicher, welche dieser Glibc-Änderungen waren dafür verantwortlich, aber eines ist klar:Es ist immer eine gute Idee, Dinge mit aktueller Software auszuführen.

Denken Sie daran, dass Blutungskanten scharf sind … seien Sie also vorsichtig da draußen.