如何在 postgresql 中改进此查询?它已经花费了超过 48 小时
Posted
技术标签:
【中文标题】如何在 postgresql 中改进此查询?它已经花费了超过 48 小时【英文标题】:How can I improve this query in postgresql? Its taking more than 48 houers already 【发布时间】:2021-09-22 10:49:38 【问题描述】:我确实有以下查询,我正在对一个 postgresql 数据库运行它,该数据库在表 account_message
中有超过 10M 的条目,在表 message
中有超过 1M 的条目。
Postgresql 的版本为PostgreSQL 11.12, compiled by Visual C++ build 1914, 64-bit
有什么办法可以让这个查询更快,因为它已经花费了超过 2 天而且还没有完成。
DELETE FROM account_message WHERE message_id in
(SELECT t2.id FROM message t2 WHERE NOT EXISTS
(SELECT 1 FROM customer t1 WHERE
t1.username = t2.username));
表account_message
具有以下列:
id (bigint)(primary key)
user_id (bigint)
message_id (bigint)
isRead (boolean)
isDeleted (boolean)
表message
具有以下列:
id (bigint)(primary key)
username (character varying)(255)
text (character varying)(10000)
details(character varying)(1000)
status(integer)
表customer
具有以下列:
username (character varying)(255)(primary key)
type(character varying)(500)
details(character varying)(10000)
status(integer)
active(boolean)
这对我有用,而且速度更快。
DELETE FROM account_message WHERE message_id IN (
SELECT m.id FROM message m
LEFT JOIN customer c ON m.username = c.username
WHERE c.username IS NULL LIMIT 1000)
【问题讨论】:
您的表是否有适当的索引,即message_id
和username
?
我如何检查这个?例如使用 pgAdmin。
我会尝试这样的事情:select * from pg_indexes where lower(tablename) in ('account_message', 'message', 'customer');
请read this 然后edit 向我们展示您的表定义和查询计划。
尝试将IN (SELECT ...)
转换成EXISTS (SELECT ...)
。
【参考方案1】:
您可以通过以下方式改进这一点
-
摆脱依赖的子查询,并且
分批进行。
尝试此操作以获取一批要删除的一千个消息 ID。 LEFT JOIN ... WHERE col IS NULL
是一种编写 WHERE NOT EXISTS
的方式,无需依赖子类。
SELECT m.id
FROM message m
LEFT JOIN customer c ON m.username = c.username
WHERE c.username IS NULL
LIMIT 1000
然后,在语句中使用子查询。重复该语句,直到它不删除任何行。
DELETE
FROM account_message
WHERE message_id IN (
SELECT m.id
FROM message m
LEFT JOIN customer c ON m.username = c.username
WHERE c.username IS NULL
LIMIT 1000)
以 1000 个批量执行此操作有助于提高性能:它将您的操作拆分为多个大小合理的数据库事务。
【讨论】:
当以 1000 个批次执行此操作时,它们何时准确执行?我确实在飞行脚本中运行它。所以通常每个像这里这样的脚本只执行一次。我必须自己管理吗?【参考方案2】:首先,尝试优化括号内的选择。比如:
DELETE FROM account_message WHERE message_id in
(
select t2.id message t2
left join customer t1 on (t1.username = t2.username)
where t2.username is NULL
)
【讨论】:
为什么应该更快? @LaurenzAlbe 消除依赖子查询有可能使其更快。 @O.Jones PostgreSQL 通常将NOT EXISTS
优化为反连接。根据我的经验,它的表现通常优于 IN (SELECT ...)
。以上是关于如何在 postgresql 中改进此查询?它已经花费了超过 48 小时的主要内容,如果未能解决你的问题,请参考以下文章