1

我有两个表: urls(带有索引页面的表,主机是索引列,3000 万行)主机(带有主机信息的表,主机是索引列,100 万行)

我的应用程序中最常见的 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 解决方案。你有什么建议吗?我应该怎么办?

4

2 回答 2

2

结合提供的索引,此查询应该很快:

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 语法可能同样快。请注意,第一个索引是部分索引,第二个索引是按第二列排序的多列索引DESC

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

关于性能优化的一般建议也适用。你知道该怎么做。

于 2012-07-09T21:05:59.047 回答
0

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

如果几乎所有东西都是垃圾邮件,并且如果“项目”,无论它们是什么,数量很少而且每个都很大,那么一个稍微不同的建议将适用。

说明:更新统计信息使优化器可以识别urlshosts表都很大(好吧,您没有向我们显示模式,因此我们不知道您的行大小)。以1开头的复合索引projects.id有望排除大部分内容,而它的第二个组件将立即按所需顺序提供其余内容,因此索引扫描很可能会成为查询计划选择的基础计划者。然后必须有一个索引以使主机查找有效;这张大表的大部分将永远不会被访问。urlsurlsurlshosts.host


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

于 2012-07-09T21:01:09.770 回答