使用NOT IN时,PostgreSQL查询速度缓慢。

8
我有一个 PostgreSQL 函数,可以非常快速地将查询结果返回到 pgadmin 的结果网格中。在内部,这是一个简单的函数,它使用 dblink 连接到另一个数据库并执行查询返回,因此我可以轻松运行该函数。
SELECT * FROM get_customer_trans();

它运行起来就像一个基本的表查询。

问题出现在我使用 NOT IN 子句时。所以我想运行以下查询,但它需要很长时间:

SELECT * FROM get_customer_trans()
WHERE user_email NOT IN 
    (SELECT do_not_email_address FROM do_not_email_tbl);

如何加快速度?这种情况下有没有比NOT IN子句更快的方法?

2个回答

21

get_customer_trans()不是一个表格 - 可能是一些存储过程,所以查询并不是真正的简单。您需要查看此存储过程的实际操作以了解为什么可能运行缓慢。

然而,无论存储过程的行为如何,添加以下索引应该会有很大帮助:

CREATE INDEX do_not_email_tbl_idx1
    ON do_not_email_tbl(do_not_email_address);

这个索引可以让NOT IN查询快速返回结果。然而,在较旧的PostgreSQL版本中,NOT IN已知存在问题-因此请确保您至少运行PostgreSQL 9.1或更高版本。

更新。尝试将查询更改为:

SELECT t.*
FROM get_customer_trans() AS t
WHERE NOT EXISTS (
    SELECT 1
    FROM do_not_email_tbl
    WHERE do_not_email_address = t.user_email
    LIMIT 1
)

这个查询没有使用 NOT IN,应该会很快。 我认为在PostgreSQL 9.2中,这个查询应该和使用 NOT IN 的查询一样快。


我已经在do_not_email_tbl表中的该列上建立了索引。请注意,正如我所提到的,该函数返回的结果非常快。SELECT * from get_customer_trans()可以迅速地将所有220万条记录返回到查询结果网格中。因此,这个函数看起来很快。我想通过获取那些不在do_not_email_tbl表中的客户来进一步过滤结果。 - Horse Voice
厉害了!!!谢谢!你确定使用select 1的逻辑是正确的吗?我不熟悉NOT EXISTS。 - Horse Voice
1
@mvp 我的猜测是 not exists 足够聪明,可以暗示 limit 1 - Clodoaldo Neto
1
@ClodoaldoNeto:确实,LIMIT 1是不必要的。(not) exists子查询计算出一个布尔值;要么存在一行或多行,要么不存在。无论哪种情况,子查询的结果都是true或false。 - wildplasser
1
刚在PostgreSQL 12中使用了“not exists”而不是“not in”,效果大不相同。 - Shadi
显示剩余2条评论

8

就这样做:

SELECT * FROM get_customer_trans() as t1 left join do_not_email_tbl as t2 
on user_email = do_not_email_address
where t2.do_not_email_address is null

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接