这是一个老生常谈的问题了,大家都知道 join 表太多不好,阿里的规范里提到不可以 join 超过3个表。这篇文章通过例子探讨下3个表以内应该用 join 还是多次查询。先说结论,推荐使用 join 语句。

首先打开 mysql 的计时功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> set profiling = 1;
mysql> show variables like "%pro%";
+------------------------------------------+-------+
| Variable_name | Value |
+------------------------------------------+-------+
| check_proxy_users | OFF |
| have_profiling | YES |
| mysql_native_password_proxy_users | OFF |
| performance_schema_max_program_instances | -1 |
| profiling | ON |
| profiling_history_size | 15 |
| protocol_version | 10 |
| proxy_user | |
| sha256_password_proxy_users | OFF |
| slave_compressed_protocol | OFF |
| stored_program_cache | 256 |
+------------------------------------------+-------+

确保 profiling 值为 ON

现在查2000条数据,获得合并查询的时间

1
mysql> select * from report_order left join order_form on report_order.order_id = order_form.order_id limit 2000;

然后分开查询

1
2
mysql> select * from report_order limit 2000;
mysql> select * from order_form where order_id in (123,123...);

然后查看时间

1
2
3
4
5
6
7
8
9
mysql> show profiles;
+----------+------------+-------------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-------------------------------------------------------------------------------------------------------------------+
| 7 | 0.05155450 | select * from report_order left join order_form on report_order.order_id = order_form.order_id limit 2000 |
| 8 | 0.01129025 | select * from report_order limit 2000 |
| 9 | 0.08883325 | select * from order_form where order_id in (123,234,345....) |
| 10 | 0.00051300 | select * from order_form where order_id = '123123' |
+----------+------------+-------------------------------------------------------------------------------------------------------------------+

可以看到,使用 join 的语句7耗时小于多次查询的语句8+9之和,因此在 join 表不多的情况下推荐使用 join。

另外,对于应该使用 in 还是多次查询的问题,可以看到使用 in 的语句9耗时远远小于不使用的语句10*2000,因此推荐使用 in。