如何处理PostgreSQL中巨大表之间的连接?

时间:2012-07-09 20:38:12

标签: database postgresql optimization join query-optimization

我有两张桌子: urls(带有索引页面的表,主机是索引列,30行行) hosts(包含主机信息的表,主机是索引列,1mln行)

我的应用程序中最常见的SELECT之一是:

SELECT urls.* FROM urls
JOIN hosts ON urls.host = hosts.host
WHERE urls.projects_id = ?
    AND hosts.is_spam IS NULL
ORDER by urls.id DESC, LIMIT ?

在urls表中行数超过100 000的项目中,查询执行速度非常慢。

由于表已经增长,查询的执行速度越来越慢。我已经阅读了很多关于NoSQL数据库(如MongoDB)的内容,这些数据库旨在处理如此庞大的表,但是将我的数据库从PgSQL更改为MongoDB对我来说是个大问题。现在我想尝试优化PgSQL解决方案。你有什么建议吗?我该怎么办?

2 个答案:

答案 0 :(得分:1)

此查询应与提供的索引快速结合:

CREATE INDEX hosts_host_idx ON hosts (host)
WHERE is_spam IS NULL;

CREATE INDEX urls_projects_id_idx ON urls (projects_id, id DESC);

SELECT *
FROM   urls u
WHERE  u.projects_id = ?
AND    EXISTS (
    SELECT 1
    FROM   hosts h USING (host)
    WHERE  h.is_spam IS NULL
    )
ORDER  BY urls.id DESC
LIMIT  ?;

指数是更重要的成分。你拥有的JOIN语法可能同样快。请注意,第一个索引是partial index,第二个索引是multicolumn index,第二列的订单为DESC

这在很大程度上取决于数据分布的具体情况,您必须使用EXPLAIN ANALYZE测试(一如既往)以了解性能以及是否使用索引。

General advice about performance optimization也适用。你知道这个演习。

答案 1 :(得分:0)

hosts.host列上添加索引(主要在hosts表中,这很重要),在urls.projects_id, urls.id上添加综合索引,运行ANALYZE语句以更新所有统计并观察亚秒级性能,无论垃圾邮件百分比如何。

如果几乎​​所有内容都是垃圾邮件,并且“项目”,无论它们是什么,数量都很少而且每个项目都非常大,那么建议会有一些不同的建议。

说明:更新统计信息使优化器可以识别出urlshosts表都非常大(嗯,你没有向我们展示架构,所以我们没有知道你的行大小)。以projects.id开头的复合索引有望 1 排除大部分urls内容,其第二个组件将立即提供所需的urls的其余部分因此,urls的索引扫描很可能是规划人员选择的查询计划的基础。因此,必须在hosts.host上建立索引才能使主机查找有效;这个大表的大部分都永远不会被访问。


1 )这里我们假设projects_id具有合理的选择性(在整个表中它不是相同的值)。