3

这是我的表架构

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,然后整个系统出现故障。我必须临时备份所有当前消息并截断该表。我不确定发生了什么,因为当我有大约 200 万条记录时一切正常

我正在使用带有默认选项的 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 配置,并按照 AH 的建议创建一个新索引

4

2 回答 2

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);
于 2012-11-24T18:40:56.477 回答
3

尝试为chatbox_id, date_created. 对于这个特定的查询,它将为您提供最大的性能。

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

UPD 我对性能不佳的猜测:

在某个时间点,表变得很大,无法进行全面扫描以收集准确的统计信息。在另一个ANALYZEPostgresql 得到了该表的错误统计信息之后。结果 - 制定了糟糕的计划,其中包括:

  1. 索引扫描chatbox_id
  2. 返回记录的排序以获得前 20 名。

由于默认配置和大量记录,在第 1 步返回,postgres 被迫在磁盘上的文件中进行排序。结果 - 表现不佳。

UPD2EXPALIN ANALYZE显示了0.376 ms时间和一个好的计划。您能否详细介绍性能不佳的案例?

于 2012-11-24T21:47:53.480 回答