2017-02-13 142 views
0

摘要:在Postgres 9.3.15上,我的開發和生產計算機上的相同查詢與生產計算機的查詢計劃相差300倍!Postgresql在不同服務器上的不同查詢計劃

我意識到「限制」和「偏移量」在Postgresql中並不是很好,但這並不能解釋爲什麼它在我的開發中速度很快並且生產速度很慢。

有什麼建議嗎?我試着改變cpu_tuple_cost(0.1〜0.5 - 沒有幫助)


我的生產服務器(天青:4個CPU,RAM 16gig)需要1100毫秒來運行此查詢:

prod=# SELECT "designs".* FROM "designs" WHERE "designs"."user_id" IN (SELECT "users"."id" FROM "users" WHERE (code_id=393)) ORDER BY updated_at desc, "designs"."updated_at" DESC LIMIT 20 OFFSET 0; 
Time: 1175.486 ms 

同時我dev服務器(Virtualbox,laptop,2 gig ram)需要4ms才能在同一個數據庫上運行相同的查詢。

dev=# SELECT "designs".* FROM "designs" WHERE "designs"."user_id" IN (SELECT "users"."id" FROM "users" WHERE (code_id=393)) ORDER BY updated_at desc, "designs"."updated_at" DESC LIMIT 20 OFFSET 0; 
Time: 4.249 ms 

生產的查詢計劃是這樣的:

prod=# explain SELECT "designs".* FROM "designs" WHERE "designs"."user_id" IN (SELECT "users"."id" FROM "users" WHERE (code_id=393)) ORDER BY updated_at desc, "designs"."updated_at" DESC LIMIT 20 OFFSET 0; 
                  QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=169.00..113691.20 rows=20 width=966) 
    -> Nested Loop Semi Join (cost=169.00..51045428.02 rows=8993 width=966) 
     -> Index Scan Backward using design_modification_date_idx on designs (cost=85.00..1510927.32 rows=538151 width=966) 
     -> Index Scan using "User_UserUID_key" on users (cost=84.00..92.05 rows=1 width=4) 
       Index Cond: (id = designs.user_id) 
       Filter: (code_id = 393) 
(6 rows) 

Time: 1.165 ms 

dev的查詢計劃是這樣的:

dev=# explain SELECT "designs".* FROM "designs" WHERE "designs"."user_id" IN (SELECT "users"."id" FROM "users" WHERE (code_id=393)) ORDER BY updated_at desc, "designs"."updated_at" DESC LIMIT 20 OFFSET 0; 
               QUERY PLAN 
----------------------------------------------------------------------------------------------------------- 
Limit (cost=5686.78..5686.83 rows=20 width=964) 
    -> Sort (cost=5686.78..5689.41 rows=1052 width=964) 
     Sort Key: designs.updated_at 
     -> Nested Loop (cost=0.71..5658.79 rows=1052 width=964) 
       -> Index Scan using code_idx on users (cost=0.29..192.63 rows=67 width=4) 
        Index Cond: (code_id = 393) 
       -> Index Scan using "Design_idx_owneruid" on designs (cost=0.42..73.58 rows=16 width=964) 
        Index Cond: (user_id = users.id) 
(8 rows) 

Time: 0.736 ms 

編輯:確定傾銷生產數據的全新副本後,我發現查詢規劃器是相同的(所以這是一個數據問題 - 對不起!)。查詢仍然很慢,但有什麼想法可以做些改進呢?我已經嘗試添加上設計(的updated_at,USER_ID)和用戶(ID,code_id)指標無濟於事

輸出解釋(分析一下,緩衝區):


Limit (cost=0.72..10390.79 rows=20 width=962) (actual time=1485.810..22025.828 rows=20 loops=1) 
    Buffers: shared hit=883264 read=164340 
    -> Nested Loop Semi Join (cost=0.72..4928529.42 rows=9487 width=962) (actual time=1485.809..22025.809 rows=20 loops=1) 
     Buffers: shared hit=883264 read=164340 
     -> Index Scan Backward using design_modification_date_idx on designs (cost=0.42..1442771.50 rows=538270 width=962) (actual time=1.737..18444.598 rows=263043 loops=1) 
       Buffers: shared hit=108266 read=149409 
     -> Index Scan using "User_UserUID_key" on users (cost=0.29..6.48 rows=1 width=4) (actual time=0.012..0.012 rows=0 loops=263043) 
       Index Cond: (id = designs.user_id) 
       Filter: (code_id = 393) 
       Rows Removed by Filter: 1 
       Buffers: shared hit=774998 read=14931 
Total runtime: 22027.477 ms 
(12 rows) 

編輯:對建議查詢的附加說明

dev=# explain (analyze) SELECT designs.* 
FROM designs 
    JOIN (SELECT * 
      FROM users 
      WHERE code_id=393 
      OFFSET 0 
     ) users 
     ON designs.user_id = users.id 
ORDER BY updated_at desc 
LIMIT 20; 


Limit (cost=0.72..13326.65 rows=20 width=962) (actual time=2597.877..95734.152 rows=20 loops=1) 
    -> Nested Loop (cost=0.72..6321154.70 rows=9487 width=962) (actual time=2597.877..95734.135 rows=20 loops=1) 
     Join Filter: (designs.user_id = users.id) 
     Rows Removed by Join Filter: 143621402 
     -> Index Scan Backward using design_modification_date_idx on designs (cost=0.42..1410571.52 rows=538270 width=962) (actual time=0.024..5217.228 rows=263043 loops=1) 
     -> Materialize (cost=0.29..1562.31 rows=608 width=4) (actual time=0.000..0.146 rows=546 loops=263043) 
       -> Subquery Scan on users (cost=0.29..1559.27 rows=608 width=4) (actual time=0.021..1.516 rows=546 loops=1) 
        -> Index Scan using code_idx on users users_1 (cost=0.29..1553.19 rows=608 width=602) (actual time=0.020..1.252 rows=546 loops=1) 
          Index Cond: (code_id = 393) 
Total runtime: 95734.353 ms 
(10 rows) 
+3

請發佈'EXPLAIN(ANALYZE,BUFFERS)'輸出。它看起來像數據庫包含不同的數據。 –

+0

你是對的 - 開發者的數據只是過時了幾天,但是將新的生產副本放到開發中導致了相同的緩慢。 我試着按照下面的@ chris-travers添加索引,但沒有運氣。 我已經將EXPLAIN(ANALYZE,BUFFERS)的輸出添加到主帖子的底部。 –

回答

1

這裏是我如何閱讀此內容。 ANALYSE和BUFFERS可能會有幫助,但我不這麼認爲。

在你的開發數據庫,​​它期望找到67個用戶,因此它首先選擇這些,然後排序然後做一個限制和一個偏移量。而對於數據量來看,這很快。

在生產上,它假定每個用戶有一個用戶並且倒退,但是每個用戶的設計數量要大得多,因此它首先沿着排序標準搜索設計,並過濾用戶。當你發現它在找到20行後可以停下來時,這是有道理的。但是數據統計數據使這個計劃成爲一個糟糕的計劃,你會得到一些檢查一堆額外記錄的東西來找到相關的記錄。

所以這是我猜測發生了什麼。請確保你明白爲什麼在你嘗試修復之前.....

現在,如果你要在用戶表上創建一個(user_id, code_id)索引,你可能會得到顯着的加速,因爲你可以避免在索引掃描階段。

另一個選項可能是在設計表上創建一個(modification_date, user_id)的索引。然而,這對我來說似乎是一個更長的鏡頭。

0

的問題是,與code_id = 393users大多與designsupdated_at,這樣的PostgreSQL HAST從designs掃描263043行它已發現有20滿足條件之前。

由於PostgreSQL沒有交叉表統計信息,它不知道它的想法是通過使用適當的索引來避免排序導致它比預期的少數掃描行更多。

你可以重寫查詢的使用又老又醜招用OFFSET 0,不更改查詢的語義,但防止PostgreSQL的從考慮可疑優化:

SELECT designs.* 
FROM designs 
    JOIN (SELECT * 
      FROM users 
      WHERE code_id=393 
      OFFSET 0 /* avoid optimizations beyond using an index for code_id */ 
     ) u 
     ON designs.user_id = users.id 
ORDER BY updated_at desc 
LIMIT 20; 

這應該給你想要的快計劃。

如果這還不足以推動PostgreSQL選擇好計劃,那麼可以通過刪除design_modification_date_idx索引來進一步幫助它,如果這是一個選項。

+0

嗨 - 感謝您的建議,我試了一下,但沒有得到性能的改善:/ –

+0

您爲這個查詢得到什麼計劃?如果問題類似於第二個計劃,則表明PostgreSQL *確實選擇了正確的計劃。無論如何,如果你想讓我看看它,運行'EXPLAIN(ANALYZE)'並將結果添加到你的問題中。 –

+0

完成 - 添加到主帖 –

相關問題