我有一個運行PHP和postgres後端(9.1)的Web應用程序。postgres查詢與高cpu採取年齡運行
大部分沉重的DB提升工作都是通過postgres存儲過程完成的。
應用程序中的一個進程是導入數據例程。存儲過程在導入時相當密集,但在開發時可以在大約15秒內導入我的測試表(大約20行數據)。
這是在我的本地桌面上使用默認postgres配置(將1GB RAM分配給VM)的4核心Ubuntu VM上完成的。我的CPU是Intel i7。
我在本地機器上使用了pg_top,SELECT過程在CPU使用率達到60%時達到峯值,然後在15秒內完成。
所以,我現在已經部署了應用程序到一個實時環境,這是一個1and1專業服務器。 32核,64GB RAM,2TB硬盤。非常昂貴和非常大的數字!
現在,在活動服務器上運行相同的導入例程需要6分鐘,而postgres SELECT語句在100%CPU上運行大約需要6分鐘。
我已經經歷了很多postgres conf設置,並且增加了內存號以匹配更高功率的盒子,但無論我改變什麼,它都不會對極差的性能產生任何影響。
有沒有人有任何想法,爲什麼查詢會表現得更糟?
這是隻有15秒一個4核VM搭配1GB RAM
但64GB RAM的32核服務器專用
東西顯然是沿線搞砸了,但我不能想出的6分鐘什麼它是:(
編輯:
確定這就是我想我已經精確定位的問題(在大的數據集需要50/60ms的,而不是10毫秒的小數據集)查詢
EXPLAIN UPDATE artwork_entity SET "updated_on"=NOW(), "category"='blah', "category:oid"=47425
WHERE artwork_entity."id" IN (
SELECT n."id" FROM (
SELECT e."id" FROM artwork_entity e
WHERE e."id"=47425 OR e."id" IN
(SELECT l."descendant_id" FROM artwork_relation l
LEFT JOIN artwork_entity e1 ON l."descendant_id"=e1."id"
WHERE l."depth">0 AND l."ancestor_id"=47425
AND (e1."category:oid"=(SELECT e2."category:oid" FROM artwork_entity e2 WHERE e2."id"=l."ancestor_id") OR e1."category:oid" IS NULL))
) AS n);
Update on artwork_entity (cost=3864.35..7743.46 rows=21118 width=451)"
-> Hash Semi Join (cost=3864.35..7743.46 rows=21118 width=451)"
Hash Cond: (artwork_entity.id = e.id)"
-> Seq Scan on artwork_entity (cost=0.00..3364.36 rows=42236 width=445)"
-> Hash (cost=3600.38..3600.38 rows=21118 width=10)"
-> Seq Scan on artwork_entity e (cost=24.84..3600.38 rows=21118 width=10)"
Filter: ((id = 47425) OR (hashed SubPlan 2))"
SubPlan 2"
-> Nested Loop Left Join (cost=0.00..24.83 rows=1 width=4)"
Filter: ((e1."category:oid" = (SubPlan 1)) OR (e1."category:oid" IS NULL))"
-> Index Scan using artwork_relation_ancestor_id_descendant_id_key on artwork_relation l (cost=0.00..8.28 rows=1 width=8)"
Index Cond: (ancestor_id = 47425)"
Filter: (depth > 0)"
-> Index Scan using artwork_entity_pkey on artwork_entity e1 (cost=0.00..8.27 rows=1 width=8)"
Index Cond: (l.descendant_id = id)"
SubPlan 1"
-> Index Scan using artwork_entity_pkey on artwork_entity e2 (cost=0.00..8.27 rows=1 width=4)"
Index Cond: (id = l.ancestor_id)"
另外,此查詢是在沒有索引添加到任何列的情況下執行的。
此外,只需要注意內部select語句只需要大約10/20ms就可以在大型數據集上運行(因此它必須是更新?)它僅從大量可用行中更新2行。
編輯2:
EXPLAIN SELECT e."id" FROM artwork_entity e
WHERE e."id"=47425 OR e."id" IN
(
SELECT l."descendant_id" FROM artwork_relation l
LEFT JOIN artwork_entity e1 ON l."descendant_id"=e1."id"
WHERE l."depth">0 AND l."ancestor_id"=47425
AND (e1."category:oid"=(SELECT e2."category:oid" FROM artwork_entity e2 WHERE e2."id"=l."ancestor_id") OR e1."category:oid" IS NULL)
)
然後它會嘗試獲取21K行的順序掃描
但是,如果我打破成兩個單獨的查詢,像這樣:
EXPLAIN SELECT e."id" FROM artwork_entity e
WHERE e."id"=47425
這隻得到1行然後查詢的另一部分
EXPLAIN SELECT l."descendant_id" FROM artwork_relation l
LEFT JOIN artwork_entity e1 ON l."descendant_id"=e1."id"
WHERE l."depth">0 AND l."ancestor_id"=47425
AND (e1."category:oid"=(SELECT e2."category:oid" FROM artwork_entity e2 WHERE e2."id"=l."ancestor_id") OR e1."category:oid" IS NULL)
也只能得到1行,但如果第二個查詢是在那裏的一部分,那麼它試圖獲得所有21k行。
怎麼回事?
編輯3:
簡化,在初始掃描下來返回21K行的聲明:
EXPLAIN SELECT e."id" FROM artwork_entity e
WHERE e."id"=47425 OR e."id" IN
(
SELECT l."descendant_id" FROM artwork_relation l
WHERE l."depth">0 AND l."ancestor_id"=47425
)
單獨運行它們都返回一行,但加在一起將查詢整個數據集。
你能顯示導入程序嗎? – 2013-02-22 00:31:44
您輸入的一些數據樣本很好。 – Kuberchaun 2013-02-22 00:52:53
在活動服務器上是否有其他用戶正在訪問數據庫? – Kuberchaun 2013-02-22 01:03:26