索引两表优化实战

一 脚本

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)

三 结论

左连接,索引建在右边,右连接,索引建在左边。

左右连接,索引相反建。

上一篇:hdu 6707 Shuffle Card


下一篇:简约个人简历