我已经把这个查询运行得很完美了,但问题是当我的4个表变得太大时,它变得非常慢。
如何优化此功能?
SELECT
all_records.user_id,
users.NAME,
users.IMAGE
FROM (
SELECT user_id FROM comments
WHERE commentable_id = #{object.id}
AND commentable_type = '#{object.class.to_s}'
UNION ALL
SELECT user_id FROM hello
WHERE helloable_id = #{object.id}
AND helloable_type = '#{object.class.to_s}'
UNION ALL
SELECT user_id FROM foo
WHERE fooable_id = #{object.id}
AND fooable_type = '#{object.class.to_s}'
UNION ALL
SELECT user_id FROM bar
WHERE barable_id = #{object.id}
AND barable_type = '#{object.class.to_s}'
) AS all_records
INNER JOIN users ON users.id = all_records.user_id
GROUP BY
all_records.user_id,
users.NAME,
users.IMAGE
LIMIT 15
查询应该做的是获取在(4)表上执行某些操作的唯一用户(原谅更改表名称)。即使使用LIMIT 15
它仍然运行缓慢,因为我认为它仍然读取所有4个表。我这样做是对还是有某种方法来优化它?
供参考:我正在使用postgres并使用rails但在find_by_sql
中执行它。
修改
当地的帖子:9.0.5; heroku postgres:9.1答案 0 :(得分:1)
按照原样提出问题:“获得15个任意行”。这应该非常快。
SELECT u.id, u.name, u.image
FROM (
SELECT id
FROM (
SELECT user_id AS id
FROM comments
WHERE commentable_id = #{object.id}
AND commentable_type = '#{object.class.to_s}'
UNION ALL
SELECT user_id
FROM hello
WHERE helloable_id = #{object.id}
AND helloable_type = '#{object.class.to_s}'
UNION ALL
SELECT user_id
FROM foo
WHERE fooable_id = #{object.id}
AND fooable_type = '#{object.class.to_s}'
UNION ALL
SELECT user_id
FROM bar
WHERE barable_id = #{object.id}
AND barable_type = '#{object.class.to_s}'
) AS a
GROUP BY id
LIMIT 15
) b
JOIN users u USING (id)
如果您正在运行PostgreSQL 9.1或更高版本,则可以简化为GROUP BY id
,假设users.id
是主键。但我采取了更激进的方法。
我提升了GROUP BY
和LIMIT
一个查询级别,希望能够在基表上实现更快的索引扫描。使用LIMIT 15
且无ORDER BY
顺序扫描不应发生。 Postgres只能从索引顶部读取元组,并在达到限制时立即停止
与此类似的情况类似:Way to try multiple SELECTs till a result is available?
只有在这里Postgres从索引中读取元组。
might
使用LEFT JOIN users
代替JOIN
(而不是我的额外子查询级别),JOIN
可能会删除行,CREATE INDEX comments_mult_idx
ON comments (commentable_id, commentable_type, user_id)
达到相同的效果从结果中删除一个更简单的查询计划。
为了获得完美的性能,您有
之类的索引user_id
在所有4个表上。 {{1}}必须是最后一栏。 Here's why