Database 如何在PostgreSQL中处理大型表之间的连接?

Database 如何在PostgreSQL中处理大型表之间的连接?,database,postgresql,optimization,join,query-optimization,Database,Postgresql,Optimization,Join,Query Optimization,我有两张桌子: URL(包含索引页的表,主机为索引列,有3000万行) 主机(包含主机信息的表,主机为索引列,1mln行) 我的应用程序中最常见的选择之一是: 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 ? 在URL表中有超过100000行的项目中

我有两张桌子: URL(包含索引页的表,主机为索引列,有3000万行) 主机(包含主机信息的表,主机为索引列,1mln行)

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

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 ?
在URL表中有超过100000行的项目中,查询执行速度非常慢


由于表的增长,查询的执行速度越来越慢。我读过很多关于NoSQL数据库(比如MongoDB)的书,它们被设计用来处理如此大的表,但将我的数据库从PgSQL更改为MongoDB对我来说是个大问题。现在我想尝试优化PgSQL解决方案。你有什么建议吗?我应该怎么做?

hosts.host
列上添加一个索引(主要在
hosts
表中,这很重要),并在
urls.projects\u id,urls.id
上添加一个复合索引,运行
ANALYZE
语句以更新所有统计数据,并观察次秒性能,而不考虑垃圾邮件百分比

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

说明:更新统计信息使优化器能够识别
url
hosts
表都非常大(您没有向我们显示模式,所以我们不知道您的行大小)。以
projects.id
开始的复合索引有望1排除大部分
URL
内容,其第二个组件将立即按所需顺序提供其余
URL
,因此很可能
URL
的索引扫描将成为规划者选择的查询计划的基础。然后,必须在主机上建立索引。主机,以使主机查找高效;这张大桌子的大部分根本不会被访问



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

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

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  ?;
指数是更重要的组成部分。现在的连接语法可能同样快。请注意,第一个索引是a,第二个索引是a,第二列上有
DESC
顺序

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


这也适用。你知道这个练习。

100k行实际上一点也不“庞大”。请对你的查询样本运行一个
explain-analyze
,并将结果添加到你的问题中,以及你在
hosts
url
表上的索引列表。100k行肯定是pg应该能够处理的,没有太多问题,除非它真的需要ressource。虽然优化可能会改善一些情况,但我想建议一些替代方案。我需要知道一些事情-为什么要分页(用于显示/减小单个读取的大小/仅用于测试)?接收的行数少于LIMIT子句指定的行数是否是不可接受的?是否可能在hosts表中没有与URL表中的记录对应的记录?在执行@Lepidosteus建议的
EXPLAIN ANALYZE
时,请使用。它会更具可读性,你可以通过这种方式发布一个链接。请同时显示正在使用的确切表格定义。psql中
\d tablename
的输出可以,或者为它们使用
CREATE TABLE
语句也可以。