我试图从一个远程服务器获取数据与JOIN子句,这只涉及远程表,但它是非常慢的,因为计划器决定从两个表获取所有的数据,并在本地合并它。当我添加WHERE子句时,它解决了这个问题,并且JOIN在远程服务器上完全执行。
问题在小例子上是可重复的:
-- remote server
create table test
(
id serial
constraint test_pk
primary key,
name text
);
create table test2
(
test_id int
constraint test2_test_id_fk
references test (id),
info text
);
SELECT查询:
SELECT "test".id FROM "test" JOIN "test2" ON "test"."id"="test2".test_id;
EXPLAIN VERBOSE的输出(空表!):
Merge Join (cost=732.29..1388.59 rows=42778 width=4)
Output: test.id
Merge Cond: (test.id = test2.test_id)
-> Sort (cost=366.15..373.46 rows=2925 width=4)
Output: test.id
Sort Key: test.id
-> Foreign Scan on public.test (cost=100.00..197.75 rows=2925 width=4)
Output: test.id
Remote SQL: SELECT id FROM public.test
-> Sort (cost=366.15..373.46 rows=2925 width=4)
Output: test2.test_id
Sort Key: test2.test_id
-> Foreign Scan on public.test2 (cost=100.00..197.75 rows=2925 width=4)
Output: test2.test_id
Remote SQL: SELECT test_id FROM public.test2
添加WHERE test.id=1
后
Foreign Scan (cost=100.00..198.75 rows=225 width=4)
Output: test.id
Relations: (public.test) INNER JOIN (public.test2)
Remote SQL: SELECT r1.id FROM (public.test r1 INNER JOIN public.test2 r2 ON (((r2.test_id = 1)) AND ((r1.id = 1))))
我使用AWS RDS Postgres v10.18在两边。
怎么回事?如何在远程服务器上强制执行?我没有发现任何关于那个问题的问题。
谢谢你的帮助。
PostgreSQL不知道它会在这些表中找到多少数据,它完全任意的猜测是不太好的。
你可以这样做:
alter server fdw options (add use_remote_estimate 'on');
计划将花费更长的时间,因为它需要多次往返于外部服务器来进行计划,但这通常是值得的。
您可以在本地端分析外表,以便将统计数据存储在本地。计划时间不应该像使用use_remote_estimate那样受影响。您需要偶尔重复,因为它们不会自动重新计算。我有过很糟糕的体验,但那是几个版本之前的事了,所以也许它已经改进了。
任何一个都可以为我修复您的复制器案例
PostgreSQL估计连接结果将由42778行组成,因此它认为本地连接表比传输大结果集更有效。
如果估计不正确,ANALYZE
两个外表得到准确的统计数据,然后再试一次。请记住,外部表不会自动分析。
一般情况下,在询问性能问题时,一定要包括EXPLAIN (ANALYZE, BUFFERS)
输出。