简单查询真的很慢

时间:2020-03-16 13:02:20

标签: sql postgresql query-performance

我有一个查询,它需要36s来执行,但我不明白为什么或如何改进它。有帮助吗?

SELECT p.* FROM products p INNER JOIN product_store ps ON p.id = ps.product_id
INNER JOIN stores s ON s.id = ps.store_id WHERE s.city = 'Berlin' GROUP BY p.id LIMIT 16 OFFSET 0;

这些是以下数字:

SELECT count(*) FROM products;

43309

SELECT count(*) FROM product_store;

1456445

SELECT count(*) FROM stores;

155

我想可能是关系表,但对于16行来说36s太多了。

您知道如何改善此查询吗?

编辑:

由于任何原因,问题不是由Postgres引起的,而是Hibernate引起的。该查询在pgAdmin 4中非常快,但在Hibernate中却非常慢。

谢谢大家!

编辑2:

分析

analysis

编辑3:

抱歉,这是我添加“ DISTINCT”时真正的问题

SELECT DISTINCT p.* FROM products p INNER JOIN product_store ps ON p.id = ps.product_id
INNER JOIN stores s ON s.id = ps.store_id WHERE s.city = 'Berlin' GROUP BY p.id LIMIT 16 OFFSET 0;

生产 analyze

本地 analyze

2 个答案:

答案 0 :(得分:3)

聚合是一个大问题。我建议改用EXISTS

SELECT p.*
FROM products p 
WHERE EXISTS (SELECT 1
              FROM product_store ps INNER JOIN
                   stores s 
                   ON s.id = ps.store_id
              WHERE p.id = ps.product_id AND s.city = 'Berlin' 
             )
LIMIT 16 OFFSET 0;

然后确保您在product_store(product_id, store_id)上具有索引。我假设您已经在stores(id)上建立了索引-因为那应该是主键。

答案 1 :(得分:1)

我建议改用IN,因为选择谓词在子查询中。如果选择谓词位于父查询中,则最好使用EXISTS。使用IN时,优化器将子查询写入视图,然后通过唯一索引联接到products表。请检查同时使用EXISTSIN的执行计划,以了解区别。

SELECT p.*
FROM products p 
WHERE p.id IN (SELECT ps.product_id
              FROM product_store ps 
              JOIN stores s ON s.id = ps.store_id
              WHERE p.id = ps.product_id AND s.city = 'Berlin' 
             )
LIMIT 16 OFFSET 0;