2013-02-22 33 views
0

我有一個運行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 
) 

單獨運行它們都返回一行,但加在一起將查詢整個數據集。

+1

你能顯示導入程序嗎? – 2013-02-22 00:31:44

+0

您輸入的一些數據樣本很好。 – Kuberchaun 2013-02-22 00:52:53

+0

在活動服務器上是否有其他用戶正在訪問數據庫? – Kuberchaun 2013-02-22 01:03:26

回答

1

好,我想通了,那麼這是一種更快的方式:不是做

而這

其中E 「ID」= 47425或E 「ID」 IN(...)

我可以刪除或聲明,只是做的報表:

SELECT e."id" FROM artwork_entity e 
WHERE 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) 
) 

不同的是現在的IN語句是深度> = 0,而不是深度> 0。原因是我實際上在深度爲0處存儲了一個與實體的自引用關係。我想我在寫這個存儲過程之後添加了這種方式,所以在它不可用的時候。

不管怎樣,在這樣做。它僅僅查找正確的行,結果是更快的查詢(12ms的不60ms的)

這個答案可能是不給任何人,雖然有用!

編輯:

我是說,這是我的解決方案,並就整體而言要好很多。

然而,現在活的服務器上它需要50秒鐘做進口(而不是6分鐘),但它仍然要快得多我的本地虛擬機(具有相同的數據集12秒)

Postgres沒有達到30%以上的CPU(在現場或本地服務器上),但由於某種原因,我的低功耗本地虛擬機的速度更快。

有什麼我失蹤或應該知道配置明智?