Database 如何在PostgreSQL中处理大型表之间的连接?
我有两张桌子: URL(包含索引页的表,主机为索引列,有3000万行) 主机(包含主机信息的表,主机为索引列,1mln行) 我的应用程序中最常见的选择之一是: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行的项目中
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
语句也可以。