简体   繁体   English

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

[英]MySQL Query Optimization using multiple joins

I'm having trouble optimizing a query and could use some help. 我在优化查询时遇到问题,可能需要一些帮助。 I'm currently pulling in events in a system that has to join several other tables to make sure the event is supposed to display, etc... The query was running smoothly (around 480ms) until I introduced another table in the mix. 我当前正在系统中加入事件,该系统必须连接其他几个表以确保该事件应该显示,等等。查询运行平稳(大约480ms),直到我在混合中引入了另一个表。 The query is as follows: 查询如下:

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

It seems that the issue lies with the event_date table, but I'm unsure how to optimize this query (I tried various views, indexes, etc... to no avail). 看来问题出在event_date表上,但我不确定如何优化此查询(我尝试了各种视图,索引等……无济于事)。 I ran EXPLAIN and received the following: http://cl.ly/image/3r3u1o0n2A46 . 我运行了EXPLAIN并收到了以下消息: http : //cl.ly/image/3r3u1o0n2A46 在此处输入图片说明

At the moment, the query is taking 6.6 seconds. 目前,查询耗时6.6秒。 Any help would be greatly appreciated. 任何帮助将不胜感激。

  • You may be able to get Using index on the event_date subquery by creating a compound index over (event_id, date, end_time) . 通过在(event_id, date, end_time)创建复合索引,您可能能够在event_date子查询上获得Using index That may turn the subquery into an index-only query, which should speed it up slightly. 这可能会将子查询变成仅索引的查询,这将稍微加快它的速度。

    The subquery might be better written as the following, without GROUP BY : 没有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 
  • I'm more concerned that your EXPLAIN shows so many tables with type=ALL . 我更担心的是,您的EXPLAIN显示这么多具有type = ALL的表。 That means it has to read every row from those tables and compare to them rows in other tables. 这意味着它必须从那些表中读取每一行,并与其他表中的行进行比较。 You can get an idea of how much work it's doing by multiplying the values in the rows column. 您可以通过将rows列中的值相乘来了解其工作量。 Basically, it's making billions of row comparisons to resolve the joins. 基本上,它正在进行数十亿行比较以解决联接问题。 As the tables grow, this query will get a lot worse. 随着表的增长,此查询将变得更糟。

  • Using LEFT [OUTER] JOIN has a specific purpose, and if you really mean to use INNER JOIN you should do that, because using an outer join where it doesn't belong can mess up the optimization. 使用LEFT [OUTER] JOIN有一个特定的目的,如果您真的想使用INNER JOIN ,则应该这样做,因为在不属于该INNER JOIN地方使用外部INNER JOIN可能会破坏优化。 Use an outer join like A LEFT JOIN B only if you want rows in A that may not have matching rows in B . 仅当您希望A中的行可能与B行不匹配时,才使用像A LEFT JOIN B这样的外部A LEFT JOIN B

    For example, I assume based on column naming convention that LEFT JOIN venue ON esf.venue_id=venue.id should be an inner join, because there should always be a venue referenced by esf.venue_id (unless esf.venue_id is sometimes null). 例如,基于列命名约定,我假设LEFT JOIN venue ON esf.venue_id=venue.id应该是内部LEFT JOIN venue ON esf.venue_id=venue.id ,因为应该始终有esf.venue_id引用的场所(除非esf.venue_id有时为null)。

  • event_search_flat should have a compound index with columns used in the WHERE clause first, then columns to join to other tables: (event_type, object_id, data_type, event_id) event_search_flat应该具有一个复合索引,该索引首先包含在WHERE子句中使用的列,然后是连接到其他表的列: (event_type, object_id, data_type, event_id)

  • ad_space should have a compound index for the join: (data_type, object_id) . ad_space应具有复合索引: (data_type, object_id) Does this need to be an inner join too? 这是否也需要成为内部联接?

  • ad_space_exclusion should have a compound index for the join: (ad_space_id, region_id) ad_space_exclusion应该为连接具有复合索引: (ad_space_id, region_id)

  • network_exclusion should have a compound index for the join: (data_type, object_id, region_id) network_exclusion应该为连接具有复合索引: (data_type, object_id, region_id)

  • venue is okay because it's doing a primary key lookup already. venue还可以,因为它已经在进行主键查找了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM