使用多个连接的MySQL查询优化

时间:2013-07-18 20:39:38

标签: mysql

我在优化查询时遇到问题,可以使用一些帮助。我正在系统中拉入事件,必须连接其他几个表,以确保事件应该显示等等...查询运行顺利(大约480ms),直到我在混合中引入另一个表。查询如下:

SELECT 
    keyword_terms, 
    `esf`.*, 
    `venue`.`name` AS venue_name, 
    ...
    `venue`.`zip`, ase.region_id, 
    (DATE(NOW()) BETWEEN...AND ase.region_id IS NULL) as featured, 
    getDistance(`venue`.`lat`, `venue`.`lng`, 36.073, -79.7903) as distance, 
    `network_exclusion`.`id` as net_exc_id
FROM (`event_search_flat` esf)
# Problematic part of query (pulling in the very next date for the event)
LEFT JOIN (
        SELECT event_id, MIN(TIMESTAMP(CONCAT(event_date.date, ' ', event_date.end_time))) AS next_date FROM event_date WHERE 
        event_date.date >= CURDATE() OR (event_date.date = CURDATE() AND TIME(event_date.end_time) >= TIME(NOW()))
        GROUP BY event_id
) edate ON edate.event_id=esf.object_id
# Pull in associated ad space
LEFT JOIN `ad_space` ads ON `ads`.`data_type`=`esf`.`data_type` AND ads.object_id=esf.object_id
# and make sure it is featured within region
LEFT JOIN `ad_space_exclusion` ase ON ase.ad_space_id=ads.id AND region_id =5
# Get venue details
LEFT JOIN `venue` ON `esf`.`venue_id`=`venue`.`id`
# Make sure this event should be listed
LEFT JOIN `network_exclusion` ON network_exclusion.data_type=esf.data_type  
                 AND network_exclusion.object_id=esf.object_id
                 AND network_exclusion.region_id=5
WHERE `esf`.`event_type` IN ('things to do') 
AND (`edate`.`next_date` >= '2013-07-18 16:23:53')
GROUP BY `esf`.`esf_id`
HAVING `net_exc_id` IS NULL
AND `distance` <= 40
ORDER BY DATE(edate.next_date) asc, 
`distance` asc
LIMIT 6

似乎问题在于event_date表,但我不确定如何优化此查询(我尝试了各种视图,索引等......无济于事)。我运行了EXPLAIN并收到以下内容:http://cl.ly/image/3r3u1o0n2A46enter image description here

目前,查询耗时6.6秒。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

  • 您可以通过在Using index上创建复合索引,在event_date子查询上获得(event_id, date, end_time)。这可能会将子查询转换为仅索引查询,这应该会稍微加快它。

    子查询可能更好地编写如下,没有GROUP BY

    SELECT event_id, TIMESTAMP(CONCAT(event_date.date, ' ', event_date.end_time))) AS next_date
    FROM event_date 
    WHERE event_date.date >= CURDATE() 
      OR (event_date.date = CURDATE() AND TIME(event_date.end_time) >= TIME(NOW()))
    ORDER BY next_date LIMIT 1
    
  • 我更担心你的EXPLAIN显示了很多 type = ALL 的表格。这意味着它必须从这些表中读取每个行,并与其他表中的行进行比较。您可以通过将列中的值相乘来了解它正在做多少工作。基本上,它正在进行数十亿行比较以解决连接问题。随着表格的增长,这个查询会变得更糟。

  • 使用LEFT [OUTER] JOIN有一个特定的目的,如果你真的想使用INNER JOIN,你应该这样做,因为使用不属于的外连接可能会使优化陷入困境。仅当您希望A LEFT JOIN B中的行可能没有A中的匹配行时,才使用B之类的外部联接。

    例如,我假设基于列命名约定LEFT JOIN venue ON esf.venue_id=venue.id应该是内连接,因为esf.venue_id应该总是有一个引用的地点(除非esf.venue_id有时为null)。

  • event_search_flat应首先使用WHERE子句中使用的列的复合索引,然后将列连接到其他表:(event_type, object_id, data_type, event_id)

  • ad_space应该有一个加入的复合索引:(data_type, object_id)。这也需要是内连接吗?

  • ad_space_exclusion应该有一个加入的复合索引:(ad_space_id, region_id)

  • network_exclusion应该有一个加入的复合索引:(data_type, object_id, region_id)

  • venue没问题,因为它已经在进行主键查找。