2010-12-02 65 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回到正轨。

相关问题