Performance

Postgres SELECT 非常慢,EXPLAIN ANALYZE SELECT 一點也不慢

  • November 10, 2020

前段時間,我的團隊注意到我們的生產伺服器上的 SELECT 查詢極其緩慢。對於超過 100 萬行的表,我們談論的是幾分鐘。這些是簡單的查詢,例如

SELECT id, name, serno FROM public.product_facts;

相比之下,這非常快:

EXPLAIN ANALYZE SELECT id, name, serno FROM public.product_facts;

後者返回如下統計資訊:

Seq Scan on product_facts (cost=0.00..58167.86 rows=1339186 width=24) (actual time=0.012..435.753 rows=1399186 loops=1)
Planning time: 0.076 ms
Execution time: 708.078 ms

同樣,這非常快:

SELECT COUNT (id) FROM public.product_facts;

伺服器記憶體和 CPU 似乎沒有徵稅。如果我在 PGadmin 的一個選項卡中執行準系統 SELECT 並讓它做它的事情,我可以在另一個選項卡或其他地方執行一個單獨的操作,它執行良好。此外,通過 檢查程序和系統消耗top,我看不到 CPU 或記憶體消耗過多的跡象。

網路滯後似乎也是一個不太可能的罪魁禍首。網路響應時間在正常範圍內。如前所述,這種奇怪的緩慢開始於幾週前,出現在我們的生產伺服器上,然後出現在我們的 UAT 上,現在也出現在我們的非生產實例上。緩慢似乎與記錄數成正比,但適用於所有表。

這個EXPLAIN ANALYZE案子對我來說是整個情況中最令人困惑的部分。從我對 Postgres 文件的閱讀中,我了解到該ANALYZE關鍵字導致伺服器實際執行有問題的命令,然後返回對該執行的分析。那麼,在這種情況下,一個查詢怎麼可能SELECT需要半秒鐘,而在另一種情況下卻超過一分鐘,而沒有任何記憶體或 CPU 過載的跡象呢?

EXPLAIN ANALYZE SELECT...執行查詢,但向客戶端發送包含執行計劃的單行,這意味著通過網路傳送幾百字節並在客戶端處理。

沒有 SELECT 的實際 SELECTEXPLAIN ANALYZE發送所有結果,這裡有超過一百萬行。當客戶端收到這些結果時,它必須對它們做一些事情。

所以可以預料,第二種形式總體上會更慢,即使幾分鐘與 708ms 確實是一個非常顯著的差異。

要解釋這種差異,需要考慮兩個因素:與網路速度相關的結果有多大,以及每行客戶端程序的成本有多大。例如,一些圖形客戶端只需將結果放入列中就需要花費大量時間。或者 psql 命令行客戶端預設格式化輸出以將列內的內容與空白填充對齊,這在某些內容上會消耗大量時間。

如果您使用的是 psql,請查看此序列需要多少時間:

\set timing on
\pset format unaligned
SELECT id, name, serno FROM public.product_facts \g /dev/null

對於通過網路發送的結果集的大小,結果SELECT sum(octet_length(concat(id,name,serno))) FROM public.product_facts應該是一個很好的大致估計。

那麼,在這種情況下,一個 SELECT 查詢怎麼可能需要半秒,而在另一種情況下卻超過一分鐘,而沒有任何記憶體或 CPU 過載的跡象呢?

我認為您正在查看伺服器,而在網路和/或客戶端電腦上發生了消耗時間的事情。伺服器可能只是將結果推送到網路套接字的速度與網路接受它們的速度一樣快,這通常不會使 CPU 保持忙碌。

引用自:https://serverfault.com/questions/1041921