一 脚本
CREATE TABLE IF NOT EXISTS `class`(
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
);
CREATE TABLE IF NOT EXISTS `book`(
`bookid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
);
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
二 实战
1 表的基本信息
mysql> select * from class;
+----+------+
| id | card |
+----+------+
| 1 | 16 |
| 2 | 12 |
| 3 | 12 |
| 4 | 1 |
| 5 | 10 |
| 6 | 7 |
| 7 | 3 |
| 8 | 13 |
| 9 | 15 |
| 10 | 17 |
| 11 | 19 |
| 12 | 3 |
| 13 | 20 |
| 14 | 8 |
| 15 | 19 |
| 16 | 12 |
| 17 | 20 |
| 18 | 7 |
| 19 | 11 |
| 20 | 17 |
+----+------+
20 rows in set (0.00 sec)
mysql> select * from book;
+--------+------+
| bookid | card |
+--------+------+
| 1 | 10 |
| 2 | 17 |
| 3 | 16 |
| 4 | 10 |
| 5 | 20 |
| 6 | 8 |
| 7 | 1 |
| 8 | 2 |
| 9 | 3 |
| 10 | 11 |
| 11 | 5 |
| 12 | 11 |
| 13 | 1 |
| 14 | 12 |
| 15 | 17 |
| 16 | 7 |
| 17 | 3 |
| 18 | 12 |
| 19 | 13 |
| 20 | 9 |
+--------+------+
20 rows in set (0.00 sec)
mysql> select * from book inner join class on book.card = class.card;
+--------+------+----+------+
| bookid | card | id | card |
+--------+------+----+------+
| 3 | 16 | 1 | 16 |
| 14 | 12 | 2 | 12 |
| 18 | 12 | 2 | 12 |
| 14 | 12 | 3 | 12 |
| 18 | 12 | 3 | 12 |
| 7 | 1 | 4 | 1 |
| 13 | 1 | 4 | 1 |
| 1 | 10 | 5 | 10 |
| 4 | 10 | 5 | 10 |
| 16 | 7 | 6 | 7 |
| 9 | 3 | 7 | 3 |
| 17 | 3 | 7 | 3 |
| 19 | 13 | 8 | 13 |
| 2 | 17 | 10 | 17 |
| 15 | 17 | 10 | 17 |
| 9 | 3 | 12 | 3 |
| 17 | 3 | 12 | 3 |
| 5 | 20 | 13 | 20 |
| 6 | 8 | 14 | 8 |
| 14 | 12 | 16 | 12 |
| 18 | 12 | 16 | 12 |
| 5 | 20 | 17 | 20 |
| 16 | 7 | 18 | 7 |
| 10 | 11 | 19 | 11 |
| 12 | 11 | 19 | 11 |
| 2 | 17 | 20 | 17 |
| 15 | 17 | 20 | 17 |
+--------+------+----+------+
27 rows in set (0.00 sec)
mysql> select * from book left join class on book.card = class.card;
+--------+------+------+------+
| bookid | card | id | card |
+--------+------+------+------+
| 3 | 16 | 1 | 16 |
| 14 | 12 | 2 | 12 |
| 18 | 12 | 2 | 12 |
| 14 | 12 | 3 | 12 |
| 18 | 12 | 3 | 12 |
| 7 | 1 | 4 | 1 |
| 13 | 1 | 4 | 1 |
| 1 | 10 | 5 | 10 |
| 4 | 10 | 5 | 10 |
| 16 | 7 | 6 | 7 |
| 9 | 3 | 7 | 3 |
| 17 | 3 | 7 | 3 |
| 19 | 13 | 8 | 13 |
| 2 | 17 | 10 | 17 |
| 15 | 17 | 10 | 17 |
| 9 | 3 | 12 | 3 |
| 17 | 3 | 12 | 3 |
| 5 | 20 | 13 | 20 |
| 6 | 8 | 14 | 8 |
| 14 | 12 | 16 | 12 |
| 18 | 12 | 16 | 12 |
| 5 | 20 | 17 | 20 |
| 16 | 7 | 18 | 7 |
| 10 | 11 | 19 | 11 |
| 12 | 11 | 19 | 11 |
| 2 | 17 | 20 | 17 |
| 15 | 17 | 20 | 17 |
| 8 | 2 | NULL | NULL |
| 11 | 5 | NULL | NULL |
| 20 | 9 | NULL | NULL |
+--------+------+------+------+
2 无索引的左连接测试
mysql> explain select * from class left join book on class.card = book.card;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | NULL |
| 1 | SIMPLE | book | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
type 有 ALL,结果很差。
3 添加索引进行优化——左连接,索引建在右表,优化成功。
mysql> alter table book add index Y(`card`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from class left join book on class.card = book.card;
+----+-------------+-------+------------+------+---------------+------+---------+-----------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-----------------+------+----------+-------------+
| 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | NULL |
| 1 | SIMPLE | book | NULL | ref | Y | Y | 4 | db01.class.card | 1 | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------+---------+-----------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
可以看到第二行的 type 变成了 ref,rows 优化也比较明显。
这是由左连接的特性决定的。left join 条件用于确定如何从右表搜索行,左边一定都有。
所以右边是关键点,一定需要建立索引。
优化成功。
4 添加索引进行优化——左连接,索引建在左表,优化失败。
mysql> drop index Y on book;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table class add index Y(`card`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from class left join book on class.card = book.card;
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | class | NULL | index | NULL | Y | 4 | NULL | 20 | 100.00 | Using index |
| 1 | SIMPLE | book | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
结果不好,优化失败。
5 删除索引
mysql> drop index Y on class;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from book;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| book | 0 | PRIMARY | 1 | bookid | A | 20 | NULL | NULL | | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
mysql> show index from class;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| class | 0 | PRIMARY | 1 | id | A | 20 | NULL | NULL | | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
6 无索引的右连接测试
mysql> explain select * from class right join book on class.card = book.card;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | book | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | NULL |
| 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
结果很差,需要优化。
7 添加索引进行优化——右连接,索引建在左表,优化成功
mysql> alter table class add index Y(`card`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from class right join book on class.card = book.card;
+----+-------------+-------+------------+------+---------------+------+---------+----------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+----------------+------+----------+-------------+
| 1 | SIMPLE | book | NULL | ALL | NULL | NULL | NULL | NULL | 20 | 100.00 | NULL |
| 1 | SIMPLE | class | NULL | ref | Y | Y | 4 | db01.book.card | 1 | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------+---------+----------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
三 结论
左连接,索引建在右边,右连接,索引建在左边。
左右连接,索引相反建。