使用ORDER BY优化PostgreSQL查询并限制1

时间:2015-10-28 15:17:09

标签: sql postgresql indexing query-optimization

我有以下PostgreSQL架构:

CREATE TABLE User (
    ID INTEGER PRIMARY KEY
);

CREATE TABLE BOX (
    ID INTEGER PRIMARY KEY 
);

CREATE SEQUENCE seq_item;

CREATE TABLE Item (
    ID INTEGER PRIMARY KEY DEFAULT nextval('seq_item'),
    SENDER INTEGER REFERENCES User(id),
    RECEIVER INTEGER REFERENCES User(id),
    INFO TEXT,
    BOX_ID INTEGER REFERENCES Box(id) NOT NULL,
    ARRIVAL TIMESTAMP
);

其主要用例是典型的生产者/消费者场景。不同的用户可以在特定用户的特定框中的数据库中插入项目,并且每个用户可以在发给她/他的框中检索最顶部(这意味着最旧的)项目。它或多或少地模仿了数据库级别的队列功能。

更确切地说,最常见的操作如下:

INSERT INTO ITEM(SENDER, RECEIVER, INFO, BOX_ID, ARRIVAL) 
VALUES (nsid, nrid, ncontent, nqid, ntime);

并根据RECEIVER+SENDERRECEIVER+BOX_ID

的组合检索命令
SELECT * INTO it FROM Item i WHERE (i.RECEIVER=? OR i.RECEIVER is NULL) AND 
(i.BOX_ID=?) ORDER BY ARRIVAL LIMIT 1;
DELETE FROM Item i WHERE i.id=it.id;

SELECT * INTO it FROM Item i WHERE (i.RECEIVER=? OR i.RECEIVER is NULL) AND 
(i.SENDER=?) ORDER BY ARRIVAL LIMIT 1;
DELETE FROM Item i WHERE i.id=it.id;

最后两个片段包装在一个存储过程中。

我想知道如何在这个用例的情况下实现最佳性能,并且知道用户将在50,000500,000项之间插入和检索(但是,数据库预计不会超过在给定点100,000个项目?)

修改

这是我EXPLAIN语句中没有索引的SELECT

Limit (cost=23.07..23.07 rows=1 width=35)
   -> Sort (cost=23.07..25.07 rows=799 width=35)
      Sort Key: ARRIVAL
      -> Seq Scan on Item i (cost=0.00..19.07 rows=799 width=35)
         Filter: (((RECEIVER = 1) OR (RECEIVER IS NULL)) AND (SENDER = 1))

根据我的理解,我得到的最好EXPLAIN就是我在时间上加上一个索引(CREATE INDEX ind ON Item(ARRIVAL);):

Limit (cost=0.42..2.88 rows=1 width=35)
   -> Index Scan using ti on Item i (cost=0.42..5899.42 rows=2397 width=35)
      Filter: (((receiver = 2) OR (RECEIVER IS NULL)) AND (SENDER = 2))

ARRIVAL上没有索引的所有情况下,我必须对表格进行排序,这似乎是我的低效率。如果我尝试在ARRIVALRECEIVER/SENDER上合并索引,我会得到相同的解释,但稍微慢一点。

假设ARRIVAL上的单个索引是最有效的选项,这是正确的吗?

1 个答案:

答案 0 :(得分:2)

关于索引,最好的方法是创建,测试查询并分析EXPLAIN计划。有时您创建索引并且刨床甚至不使用它。你会知道什么时候测试它。

默认情况下,主键获取索引,您需要为引用的表

创建索引

Postgres and Indexes on Foreign Keys and Primary Keys

您可以考虑使用where clausules上的字段创建合成索引。

请注意,即使索引改进选择,也会对插入/更新产生影响,因为索引需要重建。

但是,您必须再次测试每项更改,看看是否可以改善您的结果。