【问题标题】:Why inner join is slower than separate queries为什么内连接比单独的查询慢
【发布时间】:2014-03-13 07:50:23
【问题描述】:

我有以下表格

用户表

  • 列:ID、电子邮件
  • 索引:id

位置表

  • 列 -> id、name、user_id、last_scan_time
  • 索引:id, user_id

项目表

  • 列 -> id、name、location_id、last_scan_time
  • 索引:id, location_id

我必须运行这个查询来获取项目

select items.* from items 
inner join locations on (items.last_scan_time = locations.last_scan_time and      items.location_id = locations.id)
inner join users on (locations.user_id = users.id and users.email = 'abc@abc.com')

1056870 行的上述查询需要 13 秒

现在,如果我单独拆分每个查询而不是连接,则需要的时间会少得多

select id from users where email = 'abc@abc.com'
0.0 sec

select id,last_scan_time from locations where user_id = #user-id-returned-from-above-query#
0.0 sec

select * from items where last_scan_time = #last_scan_time-from-above-query# and  location_id = #location-id-from-above-query#
0.01 sec

我必须对连接查询或索引进行哪些更改才能使连接查询的运行速度快于单个查询的总时间?

请帮忙。

谢谢你,
萨钦

【问题讨论】:

  • explain [your query] 会告诉你发生了什么。特别是,哪些索引正在(不是?)被使用。
  • 如果您希望我们帮助优化查询,您需要向我们展示实际的表和索引定义,以及每个表的行数。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。我们还需要行计数,因为这会极大地影响查询优化。如果您知道如何进行EXPLAIN 或获得执行计划,请将结果也放入问题中。

标签: mysql sql join


【解决方案1】:

您的查询格式为(重新格式化):

SELECT i.* 
  FROM items i
  JOIN locations l 
    ON l.last_scan_time = i.last_scan_time
   AND l.id = i.location_id
  JOIN users u
    ON u.id = l.user_id 
   AND u.email = 'abc@abc.com'

所以基本上,查询中的谓词是:

  • email 表的 email 列上的 eq 文字

  • locations 表的user_id 列上的eq 引用

  • location_idlast_scan_timeitems 表上的eq 参考

这表明对于这个特定的查询,最佳索引可能是这样的:

... ON users (email,id)

... ON locations (id, last_scan_time)

... ON items (location_id, last_scan_time)

但这个建议确实取决于实际的表定义,表是 MyISAM 还是 InnoDB,基数和数据分布等等。

我推荐你使用EXPLAIN <query>来获取查询执行计划。

【讨论】:

  • 感谢 Spencer7953,在电子邮件上添加索引效果很好,它将原始查询的时间从 13 秒缩短到 0.05 秒。也非常感谢评论者指出 EXPLAIN 和基数值。它对优化有很大帮助。
【解决方案2】:

一个更好的例子是,如果您想运行一个查询,该查询涉及两组数据的交集,这两组数据在某种程度上是独立的数据部分......例如,如果您有一个事件表,事件有 EventTypes 和 EventTypes有一个属性“仅限单曲”。然后你有一个用户表,用户有 MaritalStatus,而 MaritalStatus 有一个标志“单身”。您当然还有一个将事件映射到用户的出席表。

如果您想知道是否有任何非单身人士报名参加您的仅限单身人士活动,正确的答案是不要编写一个查询,通过 ID 将这些表连接在一起,然后在 where 子句中对其进行排序.最好得到一个结果,即用户类型不是单身的用户,将结果加入到参加加入的选择中,该选择只选择事件类型为仅限单身的事件。以这种方式格式化意味着,出席表周围的 JOIN 不会加入和返回单身用户,也不会匹配仅限单身人士的事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    相关资源
    最近更新 更多