【问题标题】:MYSQL Query Slow - Sub query and Temp tableMYSQL 查询慢 - 子查询和临时表
【发布时间】:2012-12-15 19:27:48
【问题描述】:

我有这个复杂的查询,它在大约 50 毫秒内产生 3744 行。

 SELECT 
  srl.event_id as eid
 , srl.race_num as rnum
 , bts.boat_id as bid_id
 , srl.series_year as yr
 , srl.id as id 
 , IFNULL(rfi.fleet,fleet_def) as flt_old,flt_match,s.series_id as sid
 , s.series_year as syr
  ,IFNULL(ovr_pts,POINTS('4',IFNULL(ovr_place,place),num_start)) as points

 FROM

 (SELECT en1.boat_id,en1.boat_name,MAX(fleet) as fleet_def FROM entries en1 
 JOIN series_race_list srl1 ON srl1.event_id=en1.event_id 
              AND srl1.series_year=en1.race_year 
 LEFT JOIN entries_race er1 ON en1.boat_id= er1.boat_id 
                           AND srl1.event_id=en1.event_id      
                           AND srl1.series_year =en1.race_year 
 WHERE srl1.series_id ='3' AND srl1.series_year ='2012' 
                            AND en1.entry_deleted='N'      
 GROUP BY boat_id) bts 

 JOIN series_race_list srl LEFT JOIN series as s ON s.series_id=srl.series_id 
 AND s.series_year =srl.series_year 

 LEFT JOIN entries as en ON srl.event_id=en.event_id 
  AND srl.series_year =en.race_year AND bts.boat_id =en.boat_id 

 LEFT JOIN entries_race er ON er.race_id= srl.event_id AND er.race_num=srl.race_num 
                        AND er.yr = srl.series_year AND bts.boat_id =er.boat_id

 LEFT JOIN event_race_info as eri ON eri.race_id= srl.event_id 
     AND eri.race_num=srl.race_num AND eri.yr = srl.series_year 
     ANd er.line=eri.line     AND status REGEXP 'prelim|final' 

 LEFT JOIN race_results as rr ON srl.event_id=rr.race_id 
     AND srl.race_num= rr.race_num   AND srl.series_year =rr.yr 
     AND bts.boat_id= rr.boat_id AND checked_in='Y' 

LEFT JOIN race_fleet_info as rfi ON rfi.race_id= srl.event_id 
     AND rfi.yr=srl.series_year AND srl.race_num= rfi.race_num 
     AND rfi.fleet=rr.flt AND complete='Y'

LEFT JOIN series_pts_override as spo ON srl.id =spo.id AND en.boat_id =spo.bid

WHERE s.series_id ='3' AND s.series_year ='2012' AND approved ='Y'

抱歉,篇幅较长。正如我所说,这个查询在大约 50 毫秒内执行。现在我想使用这些数据并对这 3744 行结果执行查询。只要我用这样的查询来包装它

SELECT eid FROM(
     ......previous query here.....
         ) data

执行时间从 50 毫秒变为 2.5 秒哎哟!

我尝试创建一个临时表,结果是一样的。 (实际上这是我的首选方法,因为我需要对这个结果集进行一些不同的查询。

在这个网站上阅读我不认为这是一个相关的子查询,但似乎表现得像一个。

似乎创建别名表的行为是我的问题,因为子查询具有派生表别名,而临时表显然是一个表。

我怎样才能访问这 3744 行数据而不受时间限制?

如果有帮助,我可以弄清楚如何发布说明。

解释更长的查询:

id      select_type   table       type    possible_keys               key        key_len  ref                                                   rows    Extra
1       PRIMARY       <derived2>  ALL     NULL                        NULL       NULL     NULL                                                  3744
2       DERIVED       s           const   PRIMARY                     PRIMARY    5                                                              1
2       DERIVED       srl         ref     series_id,series_id_2       series_id  5                                                              16      Using where
2       DERIVED       <derived3>  ALL     NULL                        NULL       NULL     NULL                                                  208     Using join buffer
2       DERIVED       en          eq_ref  PRIMARY,event_id,event_id_2 PRIMARY    9        race_reg_test.srl.event_id,bts.boat_id                1       Using index
2       DERIVED       er          ref     PRIMARY,boat_id,boat_id_2   boat_id_2  5        bts.boat_id                                           5
2       DERIVED       eri         eq_ref  PRIMARY                     PRIMARY    13       race_reg_test.srl.event_id,race_reg_test.srl.race_... 1
2       DERIVED       rr          ref     PRIMARY,boat_id             boat_id    4        bts.boat_id                                           9
2       DERIVED       rfi         eq_ref  PRIMARY                     PRIMARY    31       race_reg_test.srl.event_id,race_reg_test.srl.race_... 1
2       DERIVED       spo         ref     PRIMARY                     PRIMARY    8        race_reg_test.srl.id,race_reg_test.en.boat_id         1
3       DERIVED       srl1        ref     series_id,series_id_2       series_id  5                                                              16      Using index; Using temporary; Using filesort
3       DERIVED       en1         ref     PRIMARY,event_id,event_id_2 PRIMARY    5        race_reg_test.srl1.event_id                           11      Using where
3       DERIVED       er1         ref     boat_id,boat_id_2           boat_id    4        race_reg_test.en1.boat_id                             9       Using index

【问题讨论】:

  • 新信息。我认为执行时间只是选择的虚假。看起来更多,看起来 Select 中的 FUNCTION 调用是主要的时间问题。仍然不知道为什么 phpmyAdmin 会给出如此不同的执行时间答案。嗯...
  • 有没有机会用视图封装一些数据集?
  • 我会尝试在打开无缓存标志的情况下运行基本查询:SELECT SQL_NO_CACHE srl.event_id ... 只是为了确保它确实在 50 毫秒内返回并且它不仅仅是从缓存。
  • 这很明显。他隐式地创建了一个包含 3744 个条目的临时表。然后将此临时表与 16*208*5*9*16*11*9 = 237219840 新行连接起来,从而产生一个具有 888151080960 行的对象。当 mysql 完成此操作时,它会使用 WHERE 语句中定义的所有内容以及应该在 wehre 语句中的所有内容(即 complete='Y')。这个大对象当然没有键,因为临时表没有。这可能需要一些时间。应该重写此查询以使用正确的连接而不是子查询。

标签: mysql subquery


【解决方案1】:

你说你尝试创建一个临时表,我不确定你的意思是不是一个视图。

我会使用该查询创建一个视图,然后在视图上执行任何必要的查询。

CREATE VIEW massive_query_view AS 
SELECT 
  srl.event_id as eid
 , srl.race_num as rnum
 , bts.boat_id as bid_id
 , srl.series_year as yr
 , srl.id as id 
 , IFNULL(rfi.fleet,fleet_def) as flt_old,flt_match,s.series_id as sid
 , s.series_year as syr
  ,IFNULL(ovr_pts,POINTS('4',IFNULL(ovr_place,place),num_start)) as points

 FROM

 (SELECT en1.boat_id,en1.boat_name,MAX(fleet) as fleet_def FROM entries en1 
 JOIN series_race_list srl1 ON srl1.event_id=en1.event_id 
              AND srl1.series_year=en1.race_year 
 LEFT JOIN entries_race er1 ON en1.boat_id= er1.boat_id 
                           AND srl1.event_id=en1.event_id      
                           AND srl1.series_year =en1.race_year 
 WHERE srl1.series_id ='3' AND srl1.series_year ='2012' 
                            AND en1.entry_deleted='N'      
 GROUP BY boat_id) bts 

 JOIN series_race_list srl LEFT JOIN series as s ON s.series_id=srl.series_id 
 AND s.series_year =srl.series_year 

 LEFT JOIN entries as en ON srl.event_id=en.event_id 
  AND srl.series_year =en.race_year AND bts.boat_id =en.boat_id 

 LEFT JOIN entries_race er ON er.race_id= srl.event_id AND er.race_num=srl.race_num 
                        AND er.yr = srl.series_year AND bts.boat_id =er.boat_id

 LEFT JOIN event_race_info as eri ON eri.race_id= srl.event_id 
     AND eri.race_num=srl.race_num AND eri.yr = srl.series_year 
     ANd er.line=eri.line     AND status REGEXP 'prelim|final' 

 LEFT JOIN race_results as rr ON srl.event_id=rr.race_id 
     AND srl.race_num= rr.race_num   AND srl.series_year =rr.yr 
     AND bts.boat_id= rr.boat_id AND checked_in='Y' 

LEFT JOIN race_fleet_info as rfi ON rfi.race_id= srl.event_id 
     AND rfi.yr=srl.series_year AND srl.race_num= rfi.race_num 
     AND rfi.fleet=rr.flt AND complete='Y'

LEFT JOIN series_pts_override as spo ON srl.id =spo.id AND en.boat_id =spo.bid

WHERE s.series_id ='3' AND s.series_year ='2012' AND approved ='Y'

然后,您可以对视图执行查询。

SELECT * FROM massive_query_view;

希望能加快速度。您可以做的另一件事是检查您的索引。索引使 where 子句更快,但插入速度更慢。有关更多信息,请查看有关 MySQL 如何使用索引的 MySQL 文档:http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

【讨论】:

    【解决方案2】:

    一些事情,但我看到的最大的事情是在您的原始查询中......在

    boat_id) bts 加入 series_race_list srl LEFT JOIN 系列为 s

    您在 bts 和 srl 之间没有“ON”条件,这将导致笛卡尔结果,并且可能对您来说是一个大杀手。对于 bts 中的每条记录,它都会在 srl 中创建一个条目,然后从该产品加入到系列中。从 srl 到系列是可以的,因为它是根据明显的有效标准/键加入的。

    接下来,您有一些不是 alias.field 的字段,例如最内层查询中的 max(fleet) 别名为“bts”。此外,如果 MAX(fleet) 按我将解释为主键并且是唯一的船 ID 分组,为什么 MAX(fleet)... 一艘船会改变它的船队吗?如果是这样,这是准确的吗?如果您有一个船队表(也有自己的自动序列 ID),并且一艘船将所有权/赞助船(无论如何)更改为预先存在的船队,例如... 船队 93 到已经拥有 ID 的新船队在 47 的档案中,尽管 47 是最新的关系,但和旧的已有 ID……那是你真正想要的吗? MAX()?

    没有 alias.field 的附加字段:ovr_pts 和 ovr_place,放在字段列表中(以及 POINTS() 函数是什么...status 在正则表达式中,在比赛结果中签入,并在比赛车队中完成info,最终在最后的 where 子句中获得批准。次要,但可能有助于索引优化。

    最后,您的查询在特定的“s.series_id... 和 s.series_year...”上有 WHERE 子句,但您在查询的前面有一个 LEFT-JOIN。这基本上取消了它的左连接组件并将其转换为隐含的 INNER JOIN,因为您不允许将 NULL 作为包含的有效选项。

    经过一些澄清后,我什至可能会建议围绕一些更改查询,但我看到的最重要的事情是从一开始......没有“ON”条件加入 bts 和 series_rate_list 表。

    【讨论】:

      猜你喜欢
      • 2014-04-30
      • 2018-08-03
      • 2013-02-27
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      相关资源
      最近更新 更多