gpt4 book ai didi

database - Postgres 触发执行速度的差异?

转载 作者:搜寻专家 更新时间:2023-10-30 23:22:55 25 4
gpt4 key购买 nike

我有一个触发器可以在表插入或更新时执行函数。它看起来像这样:

CREATE OR REPLACE FUNCTION func_fk_location_area()
RETURNS "trigger" AS $$
BEGIN
IF EXISTS (
-- there was a row valid in area when location started
SELECT * FROM location
WHERE NOT EXISTS (
SELECT * FROM area
WHERE area.key=location.key
AND area.id=location.area_id
AND ( (area.tr_from<=location.tr_from AND area.tr_until>location.tr_from) OR
(area.tr_from=location.tr_from AND area.tr_until=location.tr_from)))
) OR EXISTS (
-- there was a row valid in area when location ended
SELECT * FROM location
WHERE NOT EXISTS (
SELECT * FROM area
WHERE area.key=location.key
AND area.id=location.area_id
AND ( (area.tr_from<location.tr_until AND area.tr_until>=location.tr_until) OR
(area.tr_from=location.tr_until AND area.tr_until=location.tr_until)))
)
THEN
RAISE EXCEPTION 'FK location_area integrity violation.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_fk_area_location AFTER DELETE OR UPDATE ON area
FOR EACH ROW EXECUTE PROCEDURE func_fk_location_area();
CREATE TRIGGER trigger_fk_location_area AFTER INSERT OR UPDATE ON location
FOR EACH ROW EXECUTE PROCEDURE func_fk_location_area();

当我插入一行时,它似乎运行得很慢。使用 explain analyze,我确定此触发器需要将近 400 毫秒才能完成。

 Result  (cost=0.00..0.03 rows=1 width=0) (actual time=0.026..0.029 rows=1 loops=1)
Trigger for constraint location_fkey_tr_by: time=0.063 calls=1
Trigger trigger_fk_location_area: time=361.878 calls=1
Trigger trigger_update_objects_location: time=355.033 calls=1
Total runtime: 717.229 ms
(5 rows)

但是,如果我在函数中运行两批 SQL,它们每条只需要 3 或 4 毫秒即可运行!

第一部分:

mydb=# explain analyze
mydb-# SELECT * FROM location
mydb-# WHERE NOT EXISTS (
mydb(# SELECT * FROM area
mydb(# WHERE area.key=location.key
mydb(# AND area.id=location.area_id
mydb(# AND ( (area.tr_from<location.tr_until AND area.tr_until>=location.tr_until) OR
mydb(# (area.tr_from=location.tr_until AND area.tr_until=location.tr_until)));

Hash Anti Join (cost=14.68..146.84 rows=1754 width=126) (actual time=5.512..5.512 rows=0 loops=1)
Hash Cond: ((location.key = area.key) AND (location.area_id = area.id))
Join Filter: (((area.tr_from < location.tr_until) AND (area.tr_until >= location.tr_until)) OR ((area.tr_from = location.tr_until) AND (area.tr_until = locat
ion.tr_until)))
-> Seq Scan on location (cost=0.00..79.91 rows=2391 width=126) (actual time=0.005..1.016 rows=2393 loops=1)
-> Hash (cost=8.87..8.87 rows=387 width=37) (actual time=0.497..0.497 rows=387 loops=1)
-> Seq Scan on area (cost=0.00..8.87 rows=387 width=37) (actual time=0.004..0.250 rows=387 loops=1)
Total runtime: 5.562 ms
(7 rows)

第二部分:

mydb=# explain analyze
mydb-# SELECT * FROM location
mydb-# WHERE NOT EXISTS (
mydb(# SELECT * FROM area
mydb(# WHERE area.key=location.key
mydb(# AND area.id=location.area_id
mydb(# AND ( (area.tr_from<location.tr_until AND area.tr_until>=location.tr_until) OR
mydb(# (area.tr_from=location.tr_until AND area.tr_until=location.tr_until)));

Hash Anti Join (cost=14.68..146.84 rows=1754 width=126) (actual time=5.666..5.666 rows=0 loops=1)
Hash Cond: ((location.key = area.key) AND (location.area_id = area.id))
Join Filter: (((area.tr_from < location.tr_until) AND (area.tr_until >= location.tr_until)) OR ((area.tr_from = location.tr_until) AND (area.tr_until = locat
ion.tr_until)))
-> Seq Scan on location (cost=0.00..79.91 rows=2391 width=126) (actual time=0.005..1.072 rows=2393 loops=1)
-> Hash (cost=8.87..8.87 rows=387 width=37) (actual time=0.509..0.509 rows=387 loops=1)
-> Seq Scan on area (cost=0.00..8.87 rows=387 width=37) (actual time=0.007..0.239 rows=387 loops=1)
Total runtime: 5.725 ms
(7 rows)

这对我来说毫无意义。

有什么想法吗?

谢谢。

最佳答案

您正在设置针对每一行运行的触发器,然后在触发器函数内对整个表进行另一个选择。做一个或另一个。 (尝试将 FOR EACH ROW 更改为 FOR EACH STATEMENT。)

关于database - Postgres 触发执行速度的差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3934213/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com