我有以下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+SENDER
或RECEIVER+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,000
和500,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
上没有索引的所有情况下,我必须对表格进行排序,这似乎是我的低效率。如果我尝试在ARRIVAL
和RECEIVER/SENDER
上合并索引,我会得到相同的解释,但稍微慢一点。
假设ARRIVAL
上的单个索引是最有效的选项,这是正确的吗?
答案 0 :(得分:2)
关于索引,最好的方法是创建,测试查询并分析EXPLAIN计划。有时您创建索引并且刨床甚至不使用它。你会知道什么时候测试它。
默认情况下,主键获取索引,您需要为引用的表
创建索引Postgres and Indexes on Foreign Keys and Primary Keys
您可以考虑使用where clausules上的字段创建合成索引。
请注意,即使索引改进选择,也会对插入/更新产生影响,因为索引需要重建。
但是,您必须再次测试每项更改,看看是否可以改善您的结果。