2010-12-02 75 views
0

我們的應用程序有一個非常緩慢的聲明,它需要超過11秒,所以我想知道有什麼方法可以優化它嗎?一個緩慢的sql語句,有什麼方法可以優化它嗎?

SQL語句

SELECT id FROM mapfriends.cell_forum_topic WHERE id in (
SELECT topicid FROM mapfriends.cell_forum_item WHERE skyid=103230293 GROUP BY topicid) 
AND categoryid=29 AND hidden=false ORDER BY restoretime DESC LIMIT 10 OFFSET 0; 

    id  
--------- 
2471959 
2382296 
1535967 
2432006 
2367281 
2159706 
1501759 
1549304 
2179763 
1598043 
(10 rows) 

Time: 11444.976 ms 

計劃

friends=> explain SELECT id FROM friends.cell_forum_topic WHERE id in (
friends(> SELECT topicid FROM friends.cell_forum_item WHERE skyid=103230293 GROUP BY topicid) 
friends-> AND categoryid=29 AND hidden=false ORDER BY restoretime DESC LIMIT 10 OFFSET 0; 
                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=1443.15..1443.15 rows=2 width=12) 
    -> Sort (cost=1443.15..1443.15 rows=2 width=12) 
     Sort Key: cell_forum_topic.restoretime 
     -> Nested Loop (cost=1434.28..1443.14 rows=2 width=12) 
       -> HashAggregate (cost=1434.28..1434.30 rows=2 width=4) 
        -> Index Scan using cell_forum_item_idx_skyid on cell_forum_item (cost=0.00..1430.49 rows=1516 width=4) 
          Index Cond: (skyid = 103230293) 
       -> Index Scan using cell_forum_topic_pkey on cell_forum_topic (cost=0.00..4.40 rows=1 width=12) 
        Index Cond: (cell_forum_topic.id = cell_forum_item.topicid) 
        Filter: ((NOT cell_forum_topic.hidden) AND (cell_forum_topic.categoryid = 29)) 
(10 rows) 

Time: 1.109 ms 

指標

friends=> \d cell_forum_item 
            Table "friends.cell_forum_item" 
Column |    Type    |       Modifiers       
---------+--------------------------------+-------------------------------------------------------------- 
id  | integer      | not null default nextval('cell_forum_item_id_seq'::regclass) 
topicid | integer      | not null 
skyid | integer      | not null 
content | character varying(200)   | 
addtime | timestamp(0) without time zone | default now() 
ischeck | boolean      | 
Indexes: 
    "cell_forum_item_pkey" PRIMARY KEY, btree (id) 
    "cell_forum_item_idx" btree (topicid, skyid) 
    "cell_forum_item_idx_1" btree (topicid, id) 
    "cell_forum_item_idx_skyid" btree (skyid) 
friends=> \d cell_forum_topic 
               Table "friends.cell_forum_topic" 
    Column |    Type    |          Modifiers          

-------------+--------------------------------+------------------------------------------------------------------------------------- 
- 
id   | integer      | not null default nextval(('"friends"."cell_forum_topic_id_seq"'::text)::regclass) 
categoryid | integer      | not null 
topic  | character varying    | not null 
content  | character varying    | not null 
skyid  | integer      | not null 
addtime  | timestamp(0) without time zone | default now() 
reference | integer      | default 0 
restore  | integer      | default 0 
restoretime | timestamp(0) without time zone | default now() 
locked  | boolean      | default false 
settop  | boolean      | default false 
hidden  | boolean      | default false 
feature  | boolean      | default false 
picid  | integer      | default 29249 
managerid | integer      | 
imageid  | integer      | default 0 
pass  | boolean      | default false 
ischeck  | boolean      | 
Indexes: 
    "cell_forum_topic_pkey" PRIMARY KEY, btree (id) 
    "idx_cell_forum_topic_1" btree (categoryid, settop, hidden, restoretime, skyid) 
    "idx_cell_forum_topic_2" btree (categoryid, hidden, restoretime, skyid) 
    "idx_cell_forum_topic_3" btree (categoryid, hidden, restoretime) 
    "idx_cell_forum_topic_4" btree (categoryid, hidden, restore) 
    "idx_cell_forum_topic_5" btree (categoryid, hidden, restoretime, feature) 
    "idx_cell_forum_topic_6" btree (categoryid, settop, hidden, restoretime) 

解釋分析

mapfriends=> explain analyze SELECT id FROM mapfriends.cell_forum_topic 
mapfriends-> join (SELECT topicid FROM mapfriends.cell_forum_item WHERE  skyid=103230293 GROUP BY topicid) as tmp 
mapfriends-> on mapfriends.cell_forum_topic.id=tmp.topicid 
mapfriends-> where categoryid=29 AND hidden=false ORDER BY restoretime DESC LIMIT 10 OFFSET 0; 
                        QUERY PLAN          

------------------------------------------------------------------------------------------------------------------------------------ 
---------------------------------------------- 
Limit (cost=1446.89..1446.90 rows=2 width=12) (actual time=18016.006..18016.013 rows=10 loops=1) 
    -> Sort (cost=1446.89..1446.90 rows=2 width=12) (actual time=18016.001..18016.002 rows=10 loops=1) 
     Sort Key: cell_forum_topic.restoretime 
     Sort Method: quicksort Memory: 25kB 
     -> Nested Loop (cost=1438.02..1446.88 rows=2 width=12) (actual time=16988.492..18015.869 rows=20 loops=1) 
       -> HashAggregate (cost=1438.02..1438.04 rows=2 width=4) (actual time=15446.735..15447.243 rows=610 loops=1) 
        -> Index Scan using cell_forum_item_idx_skyid on cell_forum_item (cost=0.00..1434.22 rows=1520 width=4) (actual time=302.378..15429.782 rows=7133 loops=1) 
          Index Cond: (skyid = 103230293) 
       -> Index Scan using cell_forum_topic_pkey on cell_forum_topic (cost=0.00..4.40 rows=1 width=12) (actual time=4.210..4.210 rows=0 loops=610) 
        Index Cond: (cell_forum_topic.id = cell_forum_item.topicid) 
        Filter: ((NOT cell_forum_topic.hidden) AND (cell_forum_topic.categoryid = 29)) 
Total runtime: 18019.461 ms 
+0

編輯的答案,見下文。 – 2010-12-08 20:37:48

回答

0

問題不是由於缺乏查詢計劃的緩存,但最有可能的是由於計劃的選擇,由於缺乏適當的索引

+0

從計劃中,我們可以看到它使用了正確的索引,當我使用解釋分析時,我注意到實際的行數比較大; – francs 2010-12-02 07:55:27

+0

所以我試圖分析這個表,但它是沒有用的 – francs 2010-12-02 07:56:22

1

你能不能給我們多一些關於表格(統計)和配置的信息?

SELECT version(); 
SELECT category, name, setting FROM pg_settings WHERE name IN('effective_cache_size', 'enable_seqscan', 'shared_buffers'); 
SELECT * FROM pg_stat_user_tables WHERE relname IN('cell_forum_topic', 'cell_forum_item'); 
SELECT * FROM pg_stat_user_indexes WHERE relname IN('cell_forum_topic', 'cell_forum_item'); 
SELECT * FROM pg_stats WHERE tablename IN('cell_forum_topic', 'cell_forum_item'); 

並且在獲取此數據之前,使用ANALYZE。

它看起來像你有一個指數的一個問題,這就是所有的查詢花費它所有的時間:

- >索引掃描使用上 cell_forum_item cell_forum_item_idx_skyid(成本= 0.00..1434.22 行= 1520寬度= 4)(實際 時間= 302.378..15429.782行= 7133個 循環= 1)

如果採用真空FULL定期(不推薦!),指數膨脹可能是你的問題。一個REINDEX可能是一個好主意,只是要確定:

REINDEX TABLE cell_forum_item; 

和談論的索引,你可以將他們夫婦,這些都是過時的:

"idx_cell_forum_topic_6" btree (categoryid, settop, hidden, restoretime) 
"idx_cell_forum_topic_3" btree (categoryid, hidden, restoretime) 

其他股指也有相同的數據並且也可以被數據庫使用。


它看起來就像你有兩個問題:

  • 自動清理關閉或它的方式 後面。最後一次autovacuum是在2010年12月12日 ,你有256734死了 元組在一張表和451430死了 在其他....你必須做 這件事,這是一個 嚴重的問題。
  • 自動清理時再次工作,你 必須做一個VACUUM FULL和 REINDEX強制表重寫和 得到您的 表中除去所有空的空間。
  • 修復真空問題後,您還需要分析:數據庫 預計1520個結果,但會得到7133 結果。這可能與 統計有關,也許你必須 增加STATISTICS
  • 查詢本身也需要重寫 :它得到7133個結果,但它只需要610個結果。超過90%的 結果都丟失了......並且獲得 這7133需要很長時間,超過 15秒。通過使用沒有GROUP BY的JOIN或使用EXISTS(也沒有GROUP BY)來擺脫子查詢。

但是,在您遇到新的問題或其他問題之前,首先要讓autovacuum回到正軌。

相關問題