Postgres以错误的顺序返回记录

时间:2014-05-15 16:05:51

标签: postgresql indexing sql-order-by corruption

我有很大的表消息。它包含大约100mil的记录。

当我运行简单查询时:

select uid from messages order by uid asc limit 1000

结果很奇怪。从一开始的记录是可以的,但是它们并不总是按列 uid 排序。

   uid    
----------
 94621458 
 94637590 
 94653611 
 96545014 
 96553145 
 96581957 
 96590621 
102907437 
.....
446131576 
459475933 
424507749 
424507166 
459474125 
431059132 
440517049 
446131301 
475651666 
413687676 
.....

这是分析

 Limit  (cost=0.00..3740.51 rows=1000 width=4) (actual time=0.009..4.630 rows=1000 loops=1)
   Output: uid
   ->  Index Scan using messages_pkey on public.messages  (cost=0.00..376250123.91 rows=100587944 width=4) (actual time=0.009..4.150 rows=1000 loops=1)
         Output: uid
 Total runtime: 4.796 ms

PostgreSQL 9.1.12

表总是处于高负载(插入,更新,删除)并且几乎不断自动清空。可能导致问题吗?

UPD。添加了表定义。抱歉无法添加完整的表格定义,但所有重要字段及其类型都在这里。

# \d+ messages
                                                   Table "public.messages"
    Column    |            Type             |                       Modifiers                        | Storage  | Description
--------------+-----------------------------+--------------------------------------------------------+----------+-------------
 uid          | integer                     | not null default nextval('messages_uid_seq'::regclass) | plain    |
 code         | character(22)               | not null                                               | extended |
 created      | timestamp without time zone | not null                                               | plain    |
 accountid    | integer                     | not null                                               | plain    |
 status       | character varying(20)       | not null                                               | extended |
 hash         | character(3)                | not null                                               | extended |
 xxxxxxxx     | timestamp without time zone | not null                                               | plain    |
 xxxxxxxx     | integer                     |                                                        | plain    |
 xxxxxxxx     | character varying(255)      |                                                        | extended |
 xxxxxxxx     | text                        | not null                                               | extended |
 xxxxxxxx     | character varying(250)      | not null                                               | extended |
 xxxxxxxx     | text                        |                                                        | extended |
 xxxxxxxx     | text                        | not null                                               | extended |
Indexes:
    "messages_pkey" PRIMARY KEY, btree (uid)
    "messages_unique_code" UNIQUE CONSTRAINT, btree (code)
    "messages_accountid_created_idx" btree (accountid, created)
    "messages_accountid_hash_idx" btree (accountid, hash)
    "messages_accountid_status_idx" btree (accountid, status)
Has OIDs: no

2 个答案:

答案 0 :(得分:2)

这是一个非常一般的答案:

尝试:

SET enable_indexscan TO off;

在同一会话中重新运行查询。

如果结果的顺序与enable_indexscanon的顺序不同,则索引已损坏。

在这种情况下,请使用以下命令修复:

REINDEX INDEX index_name;

答案 1 :(得分:1)

您可以节省很长时间等待尝试在没有索引的情况下运行查询。问题很可能是由于索引损坏。立即修复它,看看是否能解决问题。

由于您的表格为is always under high load,请考虑同时构建新索引。这需要更长的时间,但不会阻止并发写入。 Per documentation on REINDEX:

  

要在不干扰生产的情况下构建索引,您应该删除   索引并重新发出CREATE INDEX CONCURRENTLY命令。

CREATE INDEX下:

CONCURRENTLY
     

使用此选项时,PostgreSQL将在不使用的情况下构建索引   采取任何阻止并发插入,更新或删除的锁   在桌子上;而标准索引构建会锁定写入(但不会   在桌面上读取,直到完成。有几点需要注意   了解何时使用此选项 - 请参阅Building Indexes Concurrently

所以我建议:

ALTER TABLE news DROP CONSTRAINT messages_pkey;
CREATE UNIQUE INDEX CONCURRENTLY messages_pkey ON news (uid);
ALTER TABLE news ADD PRIMARY KEY USING INDEX messages_pkey;

最后一步只是对系统目录的微小更新。