当前位置:Gxlcms > 数据库问题 > Mysql Join大表小表到底谁驱动谁

Mysql Join大表小表到底谁驱动谁

时间:2021-07-01 10:21:17 帮助过:4人阅读

create table dept( id int unsigned auto_increment not null primary key, name varchar(20) default ‘‘ not null, key(name) )engine=innodb default charset=utf8mb4;
CREATE TABLE `userinfo` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
  `passwd` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `phone` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `dept` int NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  KEY `name` (`name`),
  KEY `dept` (`dept`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci 

用 excel 伪造数据,并导入

mysql> load data infile /var/lib/mysql-files/new5.txt into table dept fields terminated by   lines terminated by \n;
Query OK, 1000 rows affected (0.03 sec)
Records: 1000  Deleted: 0  Skipped: 0  Warnings: 0

mysql> load data infile /var/lib/mysql-files/new.txt into table userinfo fields terminated by   lines terminated by \n;
Query OK, 120000 rows affected (0.02 sec)
Records: 120000  Deleted: 0  Skipped: 0  Warnings: 0

dept 1000 条, userinfo 120000 条

一、查找 userinfo 名字是 a25 的 id,name,及 dept name

由于有 userinfo = ‘a25‘ 的限制条件,不管谁 join 谁,或者 left join,结果都是一样的

mysql> select count(1) from userinfo left join dept using(dept_id) where userinfo.name = a25;
+----------+
| count(1) |
+----------+
|      187 |
+----------+
1 row in set

mysql> select count(1) from dept left join userinfo using(dept_id) where userinfo.name = a25;
+----------+
| count(1) |
+----------+
|      187 |
+----------+
1 row in set

mysql> select count(1) from dept join userinfo using(dept_id) where userinfo.name = a25;
+----------+
| count(1) |
+----------+
|      187 |
+----------+
1 row in set

mysql> select count(1) from userinfo join dept using(dept_id) where userinfo.name = a25;
+----------+
| count(1) |
+----------+
|      187 |
+----------+
1 row in set

那就比较四种方式的效率:

开启慢查询:

set long_query_time = 0.0001;
set global slow_query_log = ON;
mysql> show variables like "slow%";
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_launch_time    | 2                                    |
| slow_query_log      | ON                                   |
| slow_query_log_file | /var/lib/mysql/muqing-web-2-slow.log |
+---------------------+--------------------------------------+
tail -f /var/lib/mysql/muqing-web-2-slow.log // 实时查看耗时

1、userinfo left join dept

mysql> explain select userinfo.user_id, userinfo.name, dept.name from userinfo left join dept using(dept_id) where userinfo.name = a25;
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| id | select_type | table    | partitions | type   | possible_keys | key     | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | userinfo | NULL       | ref    | name,name_2   | name    | 1022    | const                 |  187 |      100 | NULL        |
|  1 | SIMPLE      | dept     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.userinfo.dept_id |    1 |      100 | Using where |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
2 rows in set

mysql> show status like last_query_cost;
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| Last_query_cost | 130.899000 |
+-----------------+------------+
1 row in set

mysql> explain select straight_join userinfo.user_id, userinfo.name, dept.name from userinfo left join dept using(dept_id) where userinfo.name = a25;
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| id | select_type | table    | partitions | type   | possible_keys | key     | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | userinfo | NULL       | ref    | name,name_2   | name    | 1022    | const                 |  187 |      100 | NULL        |
|  1 | SIMPLE      | dept     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.userinfo.dept_id |    1 |      100 | Using where |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
2 rows in set

mysql> show status like last_query_cost;
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| Last_query_cost | 130.899000 |
+-----------------+------------+
1 row in set

可以看到优化器选择的是顺序是先 userinfo 表,warnings 信息:

mysql> explain select straight_join userinfo.user_id, userinfo.name, dept.name from userinfo left join dept using(dept_id) where userinfo.name = a25;
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| id | select_type | table    | partitions | type   | possible_keys | key     | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | userinfo | NULL       | ref    | name,name_2   | name    | 1022    | const                 |  187 |      100 | NULL        |
|  1 | SIMPLE      | dept     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.userinfo.dept_id |    1 |      100 | Using where |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
2 rows in set

mysql> show warnings;
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                            |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select straight_join `test`.`userinfo`.`user_id` AS `user_id`,`test`.`userinfo`.`name` AS `name`,`test`.`dept`.`name` AS `name` from `test`.`userinfo` left join `test`.`dept` on((`test`.`userinfo`.`dept_id` = `test`.`dept`.`dept_id`)) where (`test`.`userinfo`.`name` = a25) |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set

2、userinfo join dept

mysql> explain select userinfo.user_id, userinfo.name, dept.name from userinfo join dept using(dept_id) where userinfo.name = a25;
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| id | select_type | table    | partitions | type   | possible_keys | key     | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | userinfo | NULL       | ref    | name,name_2   | name    | 1022    | const                 |  187 |      100 | NULL        |
|  1 | SIMPLE      | dept     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.userinfo.dept_id |    1 |      100 | Using where |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
2 rows in set

mysql> show status like last_query_cost;
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| Last_query_cost | 130.899000 |
+-----------------+------------+
1 row in set

mysql> explain select straight_join userinfo.user_id, userinfo.name, dept.name from userinfo join dept using(dept_id) where userinfo.name = a25;
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| id | select_type | table    | partitions | type   | possible_keys | key     | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | userinfo | NULL       | ref    | name,name_2   | name    | 1022    | const                 |  187 |      100 | NULL        |
|  1 | SIMPLE      | dept     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.userinfo.dept_id |    1 |      100 | Using where |
+----+-------------+----------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
2 rows in set

mysql> show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                         |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select straight_join `test`.`userinfo`.`user_id` AS `user_id`,`test`.`userinfo`.`name` AS `name`,`test`.`dept`.`name` AS `name` from `test`.`userinfo` join `test`.`dept` where ((`test`.`userinfo`.`name` = a25) and (`test`.`userinfo`.`dept_id` = `test`.`dept`.`dept_id`)) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set
# Time: 2020-04-10T17:00:38.452393Z
# User@Host: root[root] @ localhost []  Id:    11
# Query_time: 0.000741  Lock_time: 0.000137 Rows_sent: 187  Rows_examined: 374
SET timestamp=1586538038;
select sql_no_cache userinfo.user_id, userinfo.name, dept.name from userinfo left join dept using(dept_id) where userinfo.name = a25;
# Time: 2020-04-10T17:01:49.946904Z
# User@Host: root[root] @ localhost []  Id:    11
# Query_time: 0.000766  Lock_time: 0.000149 Rows_sent: 187  Rows_examined: 374
SET timestamp=1586538109;
select straight_join userinfo.user_id, userinfo.name, dept.name from userinfo join dept using(dept_id) where userinfo.name = a25;

可以看出两个时间差不多

3、dept left join userinfo

mysql> explain select sql_no_cache straight_join userinfo.user_id, userinfo.name, dept.name from dept left join userinfo using(dept_id) where userinfo.name = a25;

+----+-------------+----------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table    | partitions | type  | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+----------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | dept     | NULL       | index | PRIMARY       | name | 82      | NULL  | 1000 |      100 | Using index |
|  1 | SIMPLE      | userinfo | NULL       | ref   | name,name_2   | name | 1022    | const |  187 |       10 | Using where |
+----+-------------+----------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
2 rows in set

mysql> show status like last_query_cost;
+-----------------+---------------+
| Variable_name   | Value         |
+-----------------+---------------+
| Last_query_cost | 106671.417848 |
+-----------------+---------------+
1 row in set
# Time: 2020-04-10T17:32:02.890446Z
# User@Host: root[root] @  [10.0.0.105]  Id:    13
# Query_time: 0.134147  Lock_time: 0.000128 Rows_sent: 187  Rows_examined: 188000
SET timestamp=1586539922;
select sql_no_cache straight_join userinfo.user_id, userinfo.name, dept.name from dept left join userinfo using(dept_id) where userinfo.name = a25;

明显比上面的要慢

4、dept join userinfo

mysql> explain select sql_no_cache straight_join userinfo.user_id, userinfo.name, dept.name from dept join userinfo using(dept_id) where userinfo.name = a25;
+----+-------------+----------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table    | partitions | type  | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+----------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | dept     | NULL       | index | PRIMARY       | name | 82      | NULL  | 1000 |      100 | Using index |
|  1 | SIMPLE      | userinfo | NULL       | ref   | name,name_2   | name | 1022    | const |  187 |       10 | Using where |
+----+-------------+----------+------------+-------+---------------+------+---------+-------+------+----------+-------------+
2 rows in set

mysql> show status like last_query_cost;
+-----------------+---------------+
| Variable_name   | Value         |
+-----------------+---------------+
| Last_query_cost | 106671.417848 |
+-----------------+---------------+
1 row in set
# Time: 2020-04-10T17:33:35.458204Z
# User@Host: root[root] @  [10.0.0.105]  Id:    13
# Query_time: 0.133475  Lock_time: 0.000164 Rows_sent: 187  Rows_examined: 188000
SET timestamp=1586540015;
select sql_no_cache straight_join userinfo.user_id, userinfo.name, dept.name from dept join userinfo using(dept_id) where userinfo.name = a25;

速度和 3 一样,也远大于前2 

所以是大表驱动小表。而且 show status like ‘last_query_cost‘ 还挺准的

二、查找 dept 名字是 a25 的 id,name,及 dept name

 四种查询等效

mysql> select count(1) from userinfo left join dept using(dept_id) where dept.name = a25;
+----------+
| count(1) |
+----------+
|      360 |
+----------+
1 row in set

mysql> select count(1) from userinfo join dept using(dept_id) where dept.name = a25;
+----------+
| count(1) 

                  

	 	
                    
                    
                    
                    
                    
                

人气教程排行