SELECT count(*)
FROM contacts_lists
JOIN plain_contacts
ON contacts_lists.contact_id = plain_contacts.contact_id
JOIN contacts
ON contacts.id = plain_contacts.contact_id
WHERE plain_contacts.has_email
AND NOT contacts.email_bad
AND NOT contacts.email_unsub
AND contacts_lists.list_id =67339
如何优化此查询..请您解释一下......
答案 0 :(得分:7)
为了清晰起见,重新格式化您的查询计划:
QUERY PLAN Aggregate (cost=126377.96..126377.97 rows=1 width=0)
-> Hash Join (cost=6014.51..126225.38 rows=61033 width=0)
Hash Cond: (contacts_lists.contact_id = plain_contacts.contact_id)
-> Hash Join (cost=3067.30..121828.63 rows=61033 width=8)
Hash Cond: (contacts_lists.contact_id = contacts.id)
-> Index Scan using index_contacts_lists_on_list_id_and_contact_id
on contacts_lists (cost=0.00..116909.97 rows=61033 width=4)
Index Cond: (list_id = 66996)
-> Hash (cost=1721.41..1721.41 rows=84551 width=4)
-> Seq Scan on contacts (cost=0.00..1721.41 rows=84551 width=4)
Filter: ((NOT email_bad) AND (NOT email_unsub))
-> Hash (cost=2474.97..2474.97 rows=37779 width=4)
-> Seq Scan on plain_contacts (cost=0.00..2474.97 rows=37779 width=4)
Filter: has_email
两个部分索引可能根据您的数据分布消除seq扫描:
-- if many contacts have bad emails or are unsubscribed:
CREATE INDEX contacts_valid_email_idx ON contacts (id)
WHERE (NOT email_bad AND NOT email_unsub);
-- if many contacts have no email:
CREATE INDEX plain_contacts_valid_email_idx ON plain_contacts (id)
WHERE (has_email);
您可能缺少外键索引:
CREATE INDEX plain_contacts_contact_id_idx ON plain_contacts (contact_id);
最后但并非最不重要的是,如果您从未分析过数据,则需要运行:
VACUUM ANALYZE;
如果完成所有操作后仍然很慢,那么你可以做的就是没有多少合并你的plain_contacts和你的联系人表:尽管有上述索引,上述查询计划意味着你的大多数/所有订阅者都是订阅了该特定列表 - 在这种情况下,上述查询计划是您获得的最快的。
答案 1 :(得分:4)
这已经是一个非常简单的查询,数据库将以最有效的方式运行,提供统计数据是最新的
因此,就查询本身而言,没什么可做的。
在数据库管理方面,您可以添加索引 - 数据库中应该包含所有连接条件的索引,以及where子句中最具选择性的部分(list_id,contact_id为plain_contacts和contacts_lists中的FK)。这是提高此查询性能的最重要机会(数量级)。正如SpliFF指出的那样,你可能已经拥有了那些索引,所以请检查。
此外,postgres具有良好的explain命令,您应该学习和使用它。它有助于优化查询。
答案 2 :(得分:1)
由于您只想包含在连接表中设置了一些标志的行,我会将这些语句移到join子句中:
SELECT count(*)
FROM contacts_lists
JOIN plain_contacts
ON contacts_lists.contact_id = plain_contacts.contact_id
AND NOT plain_contacts.has_email
JOIN contacts
ON contacts.id = plain_contacts.contact_id
AND NOT contacts.email_unsub
AND NOT contacts.email_bad
WHERE contacts_lists.list_id =67339
我不确定这是否会对性能产生很大影响,但值得一试。您可能应该在连接表上有索引以获得最佳性能,如下所示:
plain_contacts: contact_id, has_email
contacts: id, email_unsub, email_bad
答案 3 :(得分:1)
你最近在数据库上运行过ANALYZE吗? EXPLAIN计划中的行计数看起来有意义吗? (看起来你只运行EXPLAIN.EXPLAIN ANALYZE给出估计和实际时间。)
答案 4 :(得分:0)
您可以使用SELECT count(1) ...
但除此之外我会说它看起来很好。你总是可以使用视图缓存查询的某些部分,或者在contact_id和list_id上放置索引,如果你真的很挣扎(我假设你已经有了id)。