Sama seperti tahun lalu yang berakhir, salah satu pelanggan lama kami datang kepada kami karena salah satu kueri PostgreSQL mereka yang sudah lama melibatkan perhitungan geometri PostGIS jauh lebih lambat untuk nilai tertentu. Kami meneliti masalah dan menemukan cara untuk menyelesaikannya; baca terus! Apa yang kami temukan sebagai penyebab masalah akan mengejutkan Anda!
Pengamatan awal, yang dilaporkan oleh pelanggan kami, adalah menjalankan kueri yang melibatkan ST_DistanceSpheroid
membutuhkan waktu sekitar 7 milidetik saat diminta untuk mengembalikan jarak ke POINT(33.681953 23.155994)
pada spheroid tertentu, tetapi jika titik tersebut dipindahkan ke POINT(33.681953 23.1559941)
(perbedaan hanya 0.0000001
) maka butuh 0,13 milidetik. 60 kali lebih cepat! Apa yang mungkin terjadi di Bumi (bola lain!)?
Awalnya, kami tidak dapat mereproduksi kelambatan di lingkungan pengujian kami. Di tangan kami, kedua kueri akan berkinerja sama cepatnya, tanpa pelambatan. Kami menggali ke versi perangkat lunak tertentu yang digunakan dengan pemikiran bahwa pembaruan mungkin diperlukan. Kami menggunakan versi yang dilaporkan oleh pelanggan:PostgreSQL 10.11, PostGIS 2.4.4, libproj 4.93. Kami kembali ke zaman gua dengan menurunkan versi ke versi yang tepat, tanpa hasil.
Akhirnya kami menyadari bahwa pelanggan menggunakan Ubuntu 18.04, jadi kami mencobanya ... dan lihatlah, masalahnya mereproduksi di sana. Cukuplah untuk mengatakan bahwa kami mengambil kesempatan untuk membuat profil kueri di mesin itu. Kami mendapatkan ini:
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
Omong kosong, katamu. Namun, ada sesuatu yang sangat ingin tahu tentang profil ini … dan Anda harus mengabaikan 26 baris pertama dan fokus pada __mul garis di sana. Lihat 60,82% dari waktu "diri sendiri" itu? (Saya dapat mendengar suara kesadaran yang baru saja dibuat oleh pikiran Anda). Jadi mengapa butuh begitu banyak waktu untuk titik-titik tertentu pada spheroid dan bukan yang lain? Dan juga mengapa butuh waktu lama di Ubuntu 18.04 tetapi tidak di mesin lain? Mengapa memutakhirkan PostGIS tidak menyelesaikan masalah?
Jawabannya disarankan kepada saya setelah saya menyadari apa yang jelas:PostGIS melakukan banyak trigonometri (sinus, kosinus, tangen dll) dengan memanggil libm
fungsi. Melihat log perubahan glibc, kami menemukan beberapa pengoptimalan dalam fungsi trigonometri:untuk input tertentu, perhitungan trigonometri mengambil jalan pintas yang tidak dapat diambil untuk input lain; dan pintasan semacam itu telah dioptimalkan dari waktu ke waktu. Memang, glibc mengumumkan untuk 2.27 dan 2.29 keduanya menyebutkan pengoptimalan dalam fungsi sinus/cosinus/dll. Rupanya, pernah ada beberapa pengoptimalan oleh Intel yang seharusnya memberikan hasil yang sangat akurat, tetapi kemudian seseorang menyadari bahwa klaim akurasi itu salah, jadi glibc menonaktifkan penggunaan pengoptimalan tersebut; kemudian, hal itu diterapkan kembali dengan cara yang berbeda tetapi sekali lagi dengan cepat. Atau sesuatu seperti itu — untuk orang luar seperti saya, sulit untuk mengetahui detail pastinya.
Kami menduga bahwa memutakhirkan ke versi glibc yang lebih baru akan memperbaiki masalah, membiarkan yang lainnya tetap sama. Pelanggan kami mencobanya, dan memang benar, dan mereka senang. Kami tidak begitu yakin yang mana dari perubahan glibc ini bertanggung jawab, tetapi satu hal yang jelas:selalu merupakan ide yang baik untuk menjalankan berbagai hal pada perangkat lunak terbaru.
Ingatlah bahwa tepi yang berdarah itu tajam ... jadi berhati-hatilah di luar sana.