【发布时间】:2021-06-02 22:27:12
【问题描述】:
我正在开发一个系统,任何数量的公司都可以将中小企业信息上传到数据库并进行搜索。
import_data 表存储了不同公司上传的 SME 信息。
每个公司上传的信息由表import_data的列company_id标识。
CREATE TABLE import_data
(
id uuid NOT NULL, # Indexed
company_id integer NOT NULL, # Indexed
business_name character varying, # Indexed
no_of_rating double precision, # Indexed
no_of_reviews double precision, # Indexed
phone character varying, # Indexed
email character varying, # Indexed
address character varying, # Indexed
upserted_by integer, # Not indexed
upsert_date timestamp without time zone, # Not indexed
)
PARTITION BY LIST (company_id);
现在我正在开发一个推荐系统,在该系统中,电话号码不在特定公司上传的数据中,但在另一家公司上传的数据中存在的记录被推荐给第一个购买的公司。
公司与其拥有的所有 import_data 记录之间的关系存储在另一个表import_data_company_rel 中。此表包含特定公司上传和购买的所有import_data 记录。
CREATE TABLE import_data_company_rel
(
record_id uuid NOT NULL, # Indexed
company_id integer NOT NULL # Indexed
)
PARTITION BY LIST (company_id);
两个表都进行了分区,因此每个公司都可以将他们的数据存储在自己的分区中。
例如,id 为 1 的公司会将其数据存储在 import_data_1、import_data_company_rel_1 中,id 为 2 的公司会将其数据存储在 import_data_2、import_data_company_rel_2 中,它们具有相同的表 import_data 和 import_data_company_rel 架构。
这是用于获取特定公司推荐记录的 SQL 查询,假设 id 为 1。
SELECT id,business_name,address
FROM import_data
INNER JOIN import_data_company_rel idcr ON import_data.id = idcr.record_id
WHERE idcr.company_id != 1
AND import_data.phone NOT IN (SELECT import_data.phone
FROM import_data
INNER JOIN import_data_company_rel idcr
ON import_data.id = idcr.record_id
WHERE idcr.company_id = 1)
LIMIT 100 OFFSET 0;
此查询获取首页推荐结果,电话记录不包含在公司1的记录中。
虽然这适用于少量记录,但此查询不能很好地随记录数量扩展。
当记录数以百万计的时候,为了获取100条记录,甚至一个小时后都没有完成执行。
我发现查询中减慢执行速度的部分是子查询
SELECT import_data.phone
FROM import_data
INNER JOIN import_data_company_rel idcr
ON import_data.id = idcr.record_id
WHERE idcr.company_id = 1
选择 ID 为 1 的公司已经拥有的所有电话号码,从推荐中过滤掉。此查询将逐行扫描整个表。
我认为对表进行分区与慢查询没有任何关系,因为即使没有分区,查询也很慢。
explain (analyze, buffers, format text)
结果可见https://explain.depesz.com/s/MBUL。 我正在开发 postgesql v13.2
如何加快查询速度?甚至可能吗?任何帮助表示赞赏。谢谢。
【问题讨论】:
标签: sql postgresql performance subquery