我有一个非常简单的查询,执行速度非常慢,原因是它在执行 JOIN后对视图进行扫描。看到这一点我有点惊讶,因为我希望 Postgres在加入之前进行过滤,看到其中一个基础表在要过滤的列上有一个 INDEX。
有没有办法我可以以某种方式重新排序查询或提示计划者如何以不同的方式进行查询?
请注意,我确实知道如何通过直接访问基础表来解决这个问题,但是视图隐藏了一些复杂性,最好避开查询。
查询
select * from form where encounter_id= 23728 and type = 'vitals';
解释分析
Subquery Scan on form (cost=0.57..3439.07 rows=1 width=622) (actual time=8.187..8.187 rows=0 loops=1)
Filter: ((form.encounter_id = 23728) AND (form.type = 'vitals'::text))
Rows Removed by Filter: 12000
-> Unique (cost=0.57..3259.07 rows=12000 width=626) (actual time=0.008..7.612 rows=12000 loops=1)
-> Merge Join (cost=0.57..3229.07 rows=12000 width=626) (actual time=0.007..5.485 rows=12000 loops=1)
Merge Cond: (fd.form_id = f.id)
-> Index Scan using _idx_form_details on _form_details fd (cost=0.29..2636.78 rows=12000 width=603) (actual time=0.003..1.918 rows=12000 loops=1)
-> Index Scan using pk_form on _form f (cost=0.29..412.29 rows=12000 width=27) (actual time=0.002..1.214 rows=12000 loops=1)
Planning time: 0.170 ms
Execution time: 8.212 ms
TABLE 和 VIEW 定义
CREATE TABLE _form (
id INT NOT NULL,
encounter_id INT REFERENCES _encounter (id) NOT NULL,
type TEXT NOT NULL,
CONSTRAINT pk_form PRIMARY KEY (id),
FOREIGN KEY (cid) REFERENCES _user_in_role (id)
);
CREATE INDEX encounter_id ON _form (encounter_id, type);
CREATE TABLE _form_details (
id INT NOT NULL,
form_id INT REFERENCES _form (id) NOT NULL,
archived BOOLEAN NOT NULL DEFAULT FALSE,
CONSTRAINT pk_form_details PRIMARY KEY (id),
FOREIGN KEY (cid) REFERENCES _user_in_role (id)
);
CREATE VIEW form AS
SELECT DISTINCT ON (f.id)
f.id,
f.encounter_id,
f.type,
fd.archived,
f.cid
FROM _form f
JOIN _form_details fd
ON (f.id = fd.form_id)
ORDER BY f.id, fd.id DESC;
编辑:
有人发布了一个答案(随后被删除),其中包含一个重要的信息:即使encounter_id
基础表中的列被索引,ORDER BY
视图中的操作也违背了它的目的。不幸的是,我们无法摆脱自己,ORDER BY
因为它是 DISTINCT ON
工作所必需的。