一个缓慢的sql语句,有什么方法可以优化它?

时间:2010-12-02 07:20:01

标签: postgresql

我们的应用程序声明很慢,需要11秒以上,所以我想知道有没有办法优化它?

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

2 个答案:

答案 0 :(得分: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_idx_skyid进行索引扫描   cell_forum_item(费用= 0.00..1434.22   rows = 1520 width = 4)(实际   时间= 302.378..15429.782行= 7133   循环= 1)

如果您定期使用VACUUM 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已关闭或正常 背后。最后一次autovacuum开启了 2010-12-02你死了256734 一张桌子里的元组和451430死了 在另一个......你必须这样做 关于这一点,这是一个 严重的问题。
  • 当autovacuum再次运行时,你 必须做一个VACUUM FULL和a REINDEX强制表重写和 摆脱你的所有空白空间 表。
  • 解决了真空问题之后,你 还必须分析:数据库 预计1520结果,但它得到7133 结果。这可能是一个问题 统计数据,也许你必须这样做 增加STATISTICS
  • 查询本身需要一些重写 同样:它获得了7133个结果但是它 只需要610个结果。超过90% 结果丢失了......并且得到了 这些7133耗费了大量时间 15秒通过使用不带GROUP BY的JOIN或使用EXISTS来删除子查询,也没有GROUP BY。

但是,在你遇到新问题或其他问题之前,首先要让autovacuum回到正轨。

答案 1 :(得分:0)

问题不是由于缺乏查询计划的缓存,而是由于缺乏适当的索引而导致选择计划