使用postgresql的ORDER BY,OFFSET和LIMIT优化SELECT查询

时间:2012-11-24 16:17:14

标签: postgresql

这是我的表架构

Column       |          Type          |                      Modifiers                      
-------------+------------------------+------------------------------------------------------
id           | integer                | not null default nextval('message_id_seq'::regclass)
date_created | bigint                 |
content      | text                   |
user_name    | character varying(128) |
user_id      | character varying(128) |
user_type    | character varying(8)   |
user_ip      | character varying(128) |
user_avatar  | character varying(128) |
chatbox_id   | integer                | not null
Indexes:
    "message_pkey" PRIMARY KEY, btree (id)
    "idx_message_chatbox_id" btree (chatbox_id)
    "indx_date_created" btree (date_created)
Foreign-key constraints:
    "message_chatbox_id_fkey" FOREIGN KEY (chatbox_id) REFERENCES chatboxes(id) ON UPDATE CASCADE ON DELETE CASCADE

这是查询

SELECT * 
FROM message 
WHERE chatbox_id=$1 
ORDER BY date_created 
OFFSET 0 
LIMIT 20;

($ 1将被实际ID替换)

它运行得很好,但是当它达到370万条记录时,所有SELECT查询开始消耗大量的CPU和RAM,然后整个系统崩溃。我必须暂时备份所有当前消息并截断该表。我不知道发生了什么事,因为当我有大约2百万条记录时一切正常

我正在使用Postresql Server 9.1.5和默认选项。


更新EXPLAIN ANALYZE的输出

Limit  (cost=0.00..6.50 rows=20 width=99) (actual time=0.107..0.295 rows=20 loops=1)
->  Index Scan Backward using indx_date_created on message  (cost=0.00..3458.77 rows=10646 width=99) (actual time=0.105..0.287 rows=20 loops=1)
Filter: (chatbox_id = 25065)
Total runtime: 0.376 ms
(4 rows)

更新服务器规范

Intel Xeon 5620 8x2.40GHz+HT
12GB DDR3 1333 ECC
SSD Intel X25-E Extreme 64GB

最终解决方案

最后我可以查看超过300万条消息,我必须像wildplasser建议的那样优化postgresql配置,并且还建立一个新的索引,如A.H.建议

2 个答案:

答案 0 :(得分:8)

您可以尝试为PostgreSQL提供更好的查询索引。我建议这样的事情:

create index invent_suitable_name on message(chatbox_id, date_created);

 create index invent_suitable_name on message(chatbox_id, date_created desc);

答案 1 :(得分:3)

尝试为chatbox_id, date_created添加索引。对于此特定查询,它将为您提供最佳性能。

对于这种情况,当postgres“开始消耗大量CPU和RAM”时,尝试获取更多细节。它可能是一个错误(默认配置postgres通常不会消耗太多RAM)。

UPD我对性能不佳的猜测:

在某个时间点,表格变得很大以进行全面扫描以收集准确的统计数据。在另一个ANALYZE Postgresql获得该表的错误统计信息之后。结果 - 得到了糟糕的计划,包括:

  1. chatbox_id;
  2. 上的索引扫描
  3. 订购返回的记录以获得前20名。
  4. 由于在步骤1返回的默认配置和大量记录,postgres被迫在磁盘上的文件中进行排序。结果 - 性能不佳。

    UPD2 EXPALIN ANALYZE显示0.376 ms时间和良好的计划。你能否详细介绍一个性能不佳的案例?