优化相关子查询

时间:2012-02-04 15:10:35

标签: php mysql

尝试使用corollat​​ed子查询优化此查询

SELECT g.*, g.instaLikes + (  SELECT COUNT( * )  FROM gallery_likes AS l WHERE l.gallery_id = g.id ) AS likes 
FROM gallery AS g 
WHERE (  STATUS =  'approved' ) 
ORDER BY g.moderated_at DESC , g.id ASC

没有子查询的SELECT非常快,当我尝试LEFT JOIN时它更慢。

SELECT g.*, (g.instaLikes + COUNT( l.id ) ) AS likes 
FROM gallery AS g
LEFT JOIN gallery_likes AS l ON ( g.id = l.gallery_id ) 
WHERE ( STATUS =  'approved)
GROUP BY g.id
ORDER BY g.moderated_at DESC , g.id ASC 

似乎最快的选项是单独执行查询,然后在PHP循环中将字段一起添加,因为我可以运行子查询一次,而不是在库中运行n次。

目前gallery中有2000行,gallery_likes中有15000行。我认为我还不需要进行优化,因为这些数字似乎很低,但是第一个查询需要20-30秒而LEFT JOIN需要100秒以上!

1 个答案:

答案 0 :(得分:1)

进行单独的查询并在PHP中加入数据并不是一个坏主意。但是如果你想在SQL中做同样的事情,你可以。您可以像查询表一样处理查询(即连接它),它们称为派生表。这通常是优化这些类型查询的更快捷方式。

SELECT g.*, g.instaLikes + l.c
FROM gallery AS g
LEFT JOIN (
    SELECT gallery_id, COUNT( * ) c  FROM gallery_likes GROUP BY gallery_id
) AS l ON g.id=l.gallery_id
WHERE (  STATUS =  'approved' )
ORDER BY g.moderated_at DESC , g.id ASC

这是对来自gallery_likes的所有记录进行分组,这可能非常低效。所以你应该添加一些过滤器。如果子选择(派生表)加入库并使用与外部查询相同的过滤器,则为事件。这几乎就像您的第二个查询,但它在加入之前对数据进行分组。而不是加入然后分组。

当您需要加入摘要数据(即分组依据)时,这通常是一个很好的解决方案,但有时它可能效率低下。您通常可以通过EXPLAIN告诉。