我们的 PostgreSQL 查询之一开始变慢(约 15 秒),因此我们考虑迁移到 Graph 数据库。早期的测试显示速度明显更快,太棒了。
这就是问题所在——我们仍然需要在 Postgres 中存储数据备份以满足非分析需求。Graph 数据库仅用于分析,我们希望它保留为辅助数据存储。因为我们的业务逻辑在这次迁移过程中发生了相当大的变化,两个现有的表变成了 4 个 - 而 Postgres 中当前的“备份”选择需要 1 到 6 分钟才能运行。
我尝试了几种方法来优化它,最好的方法似乎是将它变成两个查询。如果有人可以在这里提出明显的错误,我很想听听建议。我尝试在查询计划器中切换左/右/内连接,但差别不大。加入顺序确实会影响差异;我想我只是没有正确理解这一点。
我会详细介绍。
目标:检索发送给给定人员的最后 10 个附件
数据库结构:
CREATE TABLE message (
id SERIAL PRIMARY KEY NOT NULL ,
body_raw TEXT
);
CREATE TABLE attachments (
id SERIAL PRIMARY KEY NOT NULL ,
body_raw TEXT
);
CREATE TABLE message_2_attachments (
message_id INT NOT NULL REFERENCES message(id) ,
attachment_id INT NOT NULL REFERENCES attachments(id)
);
CREATE TABLE mailings (
id SERIAL PRIMARY KEY NOT NULL ,
event_timestamp TIMESTAMP not null ,
recipient_id INT NOT NULL ,
message_id INT NOT NULL REFERENCES message(id)
);
旁注:从邮件中抽象出邮件的原因是邮件通常有多个收件人/和/单个邮件可以发送给多个收件人
这个查询在一个相对较小的数据集上大约需要 5 分钟(查询规划器时间是每个项目上方的评论):
-- 159374.75
EXPLAIN ANALYZE SELECT attachments.*
FROM attachments
JOIN message_2_attachments ON attachments.id = message_2_attachments.attachment_id
JOIN message ON message_2_attachments.message_id = message.id
JOIN mailings ON mailings.message_id = message.id
WHERE mailings.recipient_id = 1
ORDER BY mailings.event_timestamp desc limit 10 ;
将其拆分为 2 个查询只需要 1/8 的时间:
-- 19123.22
EXPLAIN ANALYZE SELECT message_2_attachments.attachment_id
FROM mailings
JOIN message ON mailings.message_id = message.id
JOIN message_2_attachments ON message.id = message_2_attachments.message_id
JOIN attachments ON message_2_attachments.attachment_id = attachments.id
WHERE mailings.recipient_id = 1
ORDER BY mailings.event_timestamp desc limit 10 ;
-- 1.089
EXPLAIN ANALYZE SELECT * FROM attachments WHERE id IN ( results of above query )
我已经尝试过几次重写查询——不同的连接顺序、不同类型的连接等。我似乎无法在单个查询中实现与两个查询一样高效。
更新的 Github 有更好的格式,所以解释的完整输出在这里 - https://gist.github.com/jvanasco/bc1dd38ca06e52c9a090