我有类似的东西。通过这部分代码,我检测车辆是否至少停了5分钟。
并且工作但是,随着大量数据,它开始变慢。
我做了很多测试,我确定我的问题出在not exists
区块。
我的表:
CREATE TABLE public.messages
(
id bigint PRIMARY KEY DEFAULT nextval('messages_id_seq'::regclass),
messagedate timestamp with time zone NOT NULL,
vehicleid integer NOT NULL,
driverid integer NOT NULL,
speedeffective double precision NOT NULL,
-- ... few nonsense properties
)
WITH (
OIDS=FALSE
);
ALTER TABLE public.messages OWNER TO postgres;
CREATE INDEX idx_messages_1 ON public.messages
USING btree (vehicleid, messagedate);
我的疑问:
SELECT
*
FROM
messages m
WHERE
m.speedeffective > 0
and m.next_speedeffective = 0
and not exists( -- my problem
select id
from messages
where
vehicleid = m.vehicleid
and speedeffective > 5 -- I forgot this condition
and messagedate > m.messagedate
and messagedate <= m.messagedate + interval '5 minutes'
)
我无法弄清楚如何以更高效的方式建立这种状况。
编辑第二天:
我在 second 表中添加了一个像这样的上一个表:
WITH messagesx as (
SELECT
vehicleid,
messagedate
FROM
messages
WHERE
speedeffective > 5
)
现在效果更好。我认为我错过了一些细节。
答案 0 :(得分:0)
通常,“NOT EXISTS”会降低查询速度,因为它需要对每个外部行进行完整的表扫描。尝试在连接中包含相同的功能(我试图在这里重写查询,而不知道表,所以我可能在这里犯了错误):
SELECT
*
FROM
messages m1
LEFT JOIN
messages m2
ON m1.vehicleid = m2.vehicleid AND m1.messagedate < m2.messagedate AND m1.messagedate <= m2.messagedate+interval '5 minutes'
WHERE
speedeffective > 0
and next_speedeffective = 0
and m2.vehicleid IS NULL
请注意,NOT EXISTS被重写为未连接条件。
答案 1 :(得分:0)
根据这个答案:https://stackoverflow.com/a/36445233/5000827
阅读NOT IN
,NOT EXISTS
和LEFT JOIN
(,其中join为NULL )
对于PostgreSQL,NOT EXISTS
和LEFT JOIN
反加入并以相同的方式工作。 (这就是为什么@CountZukula答案的结果几乎与我的相同)
问题出在那种操作上:Nest
或Hash
。
所以,基于此:https://www.postgresql.org/docs/9.6/static/routine-vacuuming.html
PostgreSQL的VACUUM命令必须定期处理每个表,原因如下:
恢复或重复使用更新或删除的行占用的磁盘空间。
更新PostgreSQL查询规划器使用的数据统计信息。
更新可见性图,以加速仅索引扫描。
- 醇>
防止由于事务ID环绕或多重ID环绕而导致丢失非常旧的数据。
我制作了VACUUM ANALYZE
到消息表,同样的查询也很快。
所以,VACUUM
PostgreSQL可以更好地决定。