我有两张桌子: 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解决方案。你有什么建议吗?我该怎么办?
答案 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
语句以更新所有统计并观察亚秒级性能,无论垃圾邮件百分比如何。
如果几乎所有内容都是垃圾邮件,并且“项目”,无论它们是什么,数量都很少而且每个项目都非常大,那么建议会有一些不同的建议。
说明:更新统计信息使优化器可以识别出urls
和hosts
表都非常大(嗯,你没有向我们展示架构,所以我们没有知道你的行大小)。以projects.id
开头的复合索引有望 1 排除大部分urls
内容,其第二个组件将立即提供所需的urls
的其余部分因此,urls
的索引扫描很可能是规划人员选择的查询计划的基础。因此,必须在hosts.host
上建立索引才能使主机查找有效;这个大表的大部分都永远不会被访问。
1 )这里我们假设projects_id
具有合理的选择性(在整个表中它不是相同的值)。