我有这样的查询
SELECT DISTINCT p.id
FROM person p
INNER JOIN person_func pf1
ON p.id = pf1.person_id
INNER JOIN Func f1
ON f1.id = pf1.func_id
LEFT JOIN person_location pf2
ON p.id = pf2.person_id
LEFT JOIN Location f2
ON f2.id = pf2.location_id AND f2.val='1'
LEFT JOIN person_location pf3
ON p.id = pf3.person_id
LEFT JOIN Location f3
ON f3.id = pf3.location_id and f3.val='3'
WHERE f2.val IS NOT NULL OR f3.val IS NOT NULL;
并且共同有9-10个这样的连接。它运行得非常慢。我在person_func(person_id),person_location(person_id)上添加了索引,但它没有帮助。我该怎么做才能优化它?
示例 - SQLFiddle Example
答案 0 :(得分:1)
如果超过约5%的表格有val IS NOT NULL
(很可能就是这种情况),val
上的索引无用 {{1}条款。
但是,在您加入特定值的情况下,它可能对JOIN子句有帮助。但是,甚至更好:多列索引:
WHERE
根据具体情况(特别是,如果CREATE INDEX some_name_idx ON Location (location_id, val)
和val = 1
罕见),部分索引可能会为您提供更好的服务:
val = 3
除此之外,您需要在JOIN或WHERE条件中使用的每个列上使用索引,如果使用的值不是通用位置(小于表的约5%) - 通常是真的。 / p>
所有the usual advice for performance optimization都适用。
如果您需要更具体的建议,您需要发布很多信息。阅读tag wiki的postgresql-performance。
由于您加入了这么多表格,因此您可能会超越Postgres无法找到最佳计划的一些限制(太多可能的变化)。首先编写最具选择性的 JOIN可能很重要。通常CREATE INDEX some_name1_idx ON Location (location_id)
WHERE val = 1
CREATE INDEX some_name3_idx ON Location (location_id)
WHERE val = 3
在此案例中位于JOIN
之前。 Read more in the manual here.
LEFT JOIN
所以你有10个LEFT JOIN。示例:如果其中一半有3个匹配,则将行数乘以3 ^ 5 = 243.或者如果它们都有5个匹配,则乘以5 ^ 10 = 9765625.这必须导致可怕< / em>表现。而且一切都没有,因为你最终只想要CROSS JOIN
。
锦上添花:获得DISTINCT id
,所有这些LEFT JOIN都是100%无用的。他们不会改变一件事。只需将它们全部删除。
至于DISTINCT person.id
:将JOIN
替换为EXISTS
,以避免乘以您的行。像:
EXISTS (SELECT 1 FROM Func f1 WHERE f1.id = pf1.func_id)
答案 1 :(得分:0)
WHERE子句实际上似乎是多余的。您已经基于特定值的值加入,然后您的WHERE子句验证这些值是非NULL,所以这样做就是验证是否发生了连接。因此,如果您只获取连接发生的行,则可以使用INNER JOIN而不是LEFT JOIN。 ==&GT;如果没有发生LEFT JOIN,则f2.val将仅为空。
LEFT JOIN位置f2 ON f2.id = pf2.location_id AND f2.val ='1'
f2.val IS NOT NULL
所以,你可以在这种情况下尝试一个内连接。
您还可以识别与您想要的值对应的ID,然后加入这些ID。那些将成为主键,可能会更有效率。
识别真实问题
我还建议你逐个取出每个连接并重新运行查询,注意每次减少时间。这将有希望向您显示导致问题的join或where子句元素。