2012-10-12 89 views
3

因此,通过一些SO用户的帮助,我最终得到了一个逻辑上正确的MySQL查询,用于我正在处理的任务:检索反向按时间顺序排列的ID列表允许用户使用的新闻项目,某些类型的分组项目过滤到该组的单个代表。 (Phew!)驯服一个怪物MySQL查询

还有一个明显的问题,就是根据CakePHP的数据库调用调试打印输出,这个查询非常笨重且速度很慢,达到了145000毫秒,哎。

是否有一个明智的办法来驯服野兽像这样的,或者我应该承认,我贪多,我可以在这里咀嚼,寻找一个不太沉重的方法,将实现更多或更少类似的结果?所有建议表示赞赏

SELECT DISTINCT Uid.id, Uid.type 
    FROM (SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, 
       uids.type type 
      FROM uids 
      JOIN uids_uids ON uids_uids.uid_id = uids.id 
      JOIN aros_uids ON uids.id = aros_uids.uid_id 
      JOIN uids_uids ParentUids ON uids_uids.parent_id = ParentUids.uid_id 
      WHERE uids.type IN ('Document','Photo','Release','PreRelease', 
           'ArtworkResource','Event') 
      AND (uids.start_date IS NULL OR uids.start_date <= NOW()) 
      AND (uids.end_date IS NULL OR uids.end_date <= NOW()) 
      AND aros_uids.aro_id IN (3,2,86,1448) 
     ) Uid 
    JOIN (SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate 
      FROM uids JOIN uids_uids 
      ON uids_uids.uid_id = uids.id 
      GROUP BY uids_uids.parent_id, uids.type) T2 
    ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate 
    ORDER BY Uid.date DESC 
    LIMIT 100 

ETA:

好了,在第一遍,我转身的子查询到意见,所以现在查询看起来像一个稍微更易于管理

SELECT DISTINCT Uid.id, Uid.type 
    FROM UidView Uid 
    JOIN UidView2 T2 
    ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate 
    WHERE Uid.aro_id IN (3,2,86,1448) 
    ORDER BY Uid.date DESC 
    LIMIT 100 

这一定帮助,将Cake的估计查询时间从六位数降低到2500位左右。绝对是一个好开始!

+1

我给你一件事 - 那就是在一个查询中查看很多'uids',并让你的头... – nickhar

+0

@nickhar告诉我有关它!在我的防守中,我没有设置任何这些,我只是试图慢慢地把它摔成一个易于管理的状态。网站上的每个项目都有一个uid,通过uids_uids表连接到其他uid。有很多“WHERE uids_uids.uid_id = uid.id”类型的东西:) – thesunneversets

+1

你有我的同情心。一个uid_uid表!!尼斯。我会捕获这种结构并将其提交给编码恐怖。 – nickhar

回答

0

这里是我想尝试:

以每个派生的查询和独立运行的EXPLAIN针对每个。如评论所示,检查任何缺少索引并在需要时添加的行。发布您的EXPLAIN结果以获得任何帮助。所以

EXPLAIN SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, .... 
EXPLAIN SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate .... 

如果添加索引不帮助或帮助不大,然后把每个子查询到一个临时表第一,并应用指标到它:这些表

CREATE TABLE temp_uid 
SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, 
      uids.type type 
     FROM uids 
     JOIN uids_uids ON uids_uids.uid_id = uids.id 
     JOIN aros_uids ON uids.id = aros_uids.uid_id 
     JOIN uids_uids ParentUids ON uids_uids.parent_id = ParentUids.uid_id 
     WHERE uids.type IN ('Document','Photo','Release','PreRelease', 
          'ArtworkResource','Event') 
     AND (uids.start_date IS NULL OR uids.start_date <= NOW()) 
     AND (uids.end_date IS NULL OR uids.end_date <= NOW()) 
     AND aros_uids.aro_id IN (3,2,86,1448); 

CREATE TABLE temp_t2 
SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate 
     FROM uids JOIN uids_uids 
     ON uids_uids.uid_id = uids.id 
     GROUP BY uids_uids.parent_id, uids.type; 

而且JOIN

SELECT DISTINCT Uid.id, Uid.type 
FROM temp_uid AS Uid 
JOIN temp_t2 AS T2 ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate 
ORDER BY Uid.date DESC 
LIMIT 100; 

正如我所提到的,您可能需要添加索引,并且可能会添加到临时表中的这些列中:

ALTER TABLE temp_uid ADD INDEX parentDateIdx (parent_id, Uid.date); 
ALTER TABLE temp_t2 ADD INDEX parentMaxDateIdx (parent_id, maxdate); 

如果您需要刷新临时表,只需截断它们并对它们执行INSERT INTO temp_uid...SELECTINSERT INTO temp_t2...SELECT而不是CREATE...SELECT。存储过程对此非常有用。

顺便说一句,执行CREATE TABLE temp_t2...SELECT,我为每个临时表执行的方式可能无法创建最佳表结构,因此最好修改后续创建或从头开始自己完成。

+0

干杯,这看起来像一个明智的做法。我尝试了类似的东西,但是使用视图而不是表格。 CREATE TABLE可能产生更好的结果吗? – thesunneversets

+0

我相信它应该,尤其是当您将索引添加到这些临时表的列时。尽管如此,你确实需要进行测试。并且不要忽视为所有这些uid的表添加索引。这里是我的创建表格示例[链接](http://dev.mysql.com/doc/refman/5.0/en/create-table-select.html)上的文档,并插入... select [link](http ://dev.mysql.com/doc/refman/5.1/en/insert-select.html) – Carlos