我一直在分析我正在处理的应用程序中的一些查询,我遇到了一个查询,它检索的行数超过了必要的行数,结果集在应用程序代码中被修剪掉了。
将 LEFT JOIN 更改为 INNER JOIN 会将结果集修剪为所需的内容,并且可能还会提高性能(因为选择的行更少)。实际上,LEFT JOIN'ed 查询的性能优于 INNER JOIN'ed,只需一半的时间即可完成。
LEFT JOIN:(总共 127 行,查询耗时 0.0011 秒)
INNER JOIN:(总共 10 行,查询耗时 0.0024 秒)
(我多次运行查询,这些都是平均值)。
在两者上运行 EXPLAIN 不会显示任何解释性能差异的信息:
对于内部联接:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE contacts index NULL name 302 NULL 235 Using where
1 SIMPLE lists eq_ref PRIMARY PRIMARY 4 contacts.list_id 1
1 SIMPLE lists_to_users eq_ref PRIMARY PRIMARY 8 lists.id,const 1
1 SIMPLE tags eq_ref PRIMARY PRIMARY 4 lists_to_users.tag_id 1
1 SIMPLE users eq_ref email_2 email_2 302 contacts.email 1 Using where
对于左连接:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE contacts index NULL name 302 NULL 235 Using where
1 SIMPLE lists eq_ref PRIMARY PRIMARY 4 contacts.list_id 1
1 SIMPLE lists_to_users eq_ref PRIMARY PRIMARY 8 lists.id,const 1
1 SIMPLE tags eq_ref PRIMARY PRIMARY 4 lists_to_users.tag_id 1
1 SIMPLE users eq_ref email_2 email_2 302 contacts.email 1
和查询本身:
SELECT `contacts`.*, `lists`.`name` AS `group`, `lists`.`id` AS `group_id`, `lists`.`shared_yn`, `tags`.`name` AS `context`, `tags`.`id` AS `context_id`, `tags`.`color` AS `context_color`, `users`.`id` AS `user_id`, `users`.`avatar`
FROM `contacts`
LEFT JOIN `lists` ON lists.id=contacts.list_id
LEFT JOIN `lists_to_users` ON lists_to_users.list_id=lists.id AND lists_to_users.user_id='1' AND lists_to_users.creator='1'
LEFT JOIN `tags` ON tags.id=lists_to_users.tag_id
INNER JOIN `users` ON users.email=contacts.email
WHERE (contacts.user_id='1')
ORDER BY `contacts`.`name` ASC
(我正在谈论的子句是“用户”表上的最后一个 INNER JOIN)
该查询在 MySQL 5.1 数据库上运行,如果它有所作为的话。
有没有人知道为什么在这种情况下 LEFT JOIN'ed 查询优于 INNER JOIN'ed ?
更新:由于 Tomalak 建议我使用的小表使 INNER JOIN 更加复杂,我创建了一个包含一些模拟数据的测试数据库。'users' 表是 5000 行,contacts 表是 ~500,000 行。结果是一样的(时间也没有改变,当你考虑到现在桌子更大时,这很令人惊讶)。
我还在联系人表上运行了 ANALYZE 和 OPTIMIZE。没有任何明显的区别。