索引三表优化实战

一 脚本

CREATE TABLE IF NOT EXISTS `phone`(
`phoneid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
)ENGINE = INNODB;

INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
mysql> select * from phone;
+---------+------+
| phoneid | card |
+---------+------+
|       1 |    5 |
|       2 |   15 |
|       3 |    2 |
|       4 |    3 |
|       5 |    8 |
|       6 |   12 |
|       7 |   15 |
|       8 |   17 |
|       9 |   19 |
|      10 |    3 |
|      11 |   17 |
|      12 |   17 |
|      13 |   13 |
|      14 |   15 |
|      15 |   13 |
|      16 |   20 |
|      17 |    2 |
|      18 |    9 |
|      19 |   17 |
|      20 |   17 |
+---------+------+
20 rows in set (0.00 sec)

# 其它两张表脚本参考《索引两表优化实战》

二 实战

1 确保要操作的三张表都没有建索引

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)

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 phone;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| phone |          0 | PRIMARY  |            1 | phoneid     | A         |          20 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

2 需要执行的业务操作

mysql> select * from class LEFT JOIN book on class.card = book.card LEFT JOIN phone on book.card = phone.card;
+----+------+--------+------+---------+------+
| id | card | bookid | card | phoneid | card |
+----+------+--------+------+---------+------+
|  7 |    3 |      9 |    3 |       4 |    3 |
| 12 |    3 |      9 |    3 |       4 |    3 |
|  7 |    3 |     17 |    3 |       4 |    3 |
| 12 |    3 |     17 |    3 |       4 |    3 |
| 14 |    8 |      6 |    8 |       5 |    8 |
|  2 |   12 |     14 |   12 |       6 |   12 |
|  3 |   12 |     14 |   12 |       6 |   12 |
| 16 |   12 |     14 |   12 |       6 |   12 |
|  2 |   12 |     18 |   12 |       6 |   12 |
|  3 |   12 |     18 |   12 |       6 |   12 |
| 16 |   12 |     18 |   12 |       6 |   12 |
| 10 |   17 |      2 |   17 |       8 |   17 |
| 20 |   17 |      2 |   17 |       8 |   17 |
| 10 |   17 |     15 |   17 |       8 |   17 |
| 20 |   17 |     15 |   17 |       8 |   17 |
|  7 |    3 |      9 |    3 |      10 |    3 |
| 12 |    3 |      9 |    3 |      10 |    3 |
|  7 |    3 |     17 |    3 |      10 |    3 |
| 12 |    3 |     17 |    3 |      10 |    3 |
| 10 |   17 |      2 |   17 |      11 |   17 |
| 20 |   17 |      2 |   17 |      11 |   17 |
| 10 |   17 |     15 |   17 |      11 |   17 |
| 20 |   17 |     15 |   17 |      11 |   17 |
| 10 |   17 |      2 |   17 |      12 |   17 |
| 20 |   17 |      2 |   17 |      12 |   17 |
| 10 |   17 |     15 |   17 |      12 |   17 |
| 20 |   17 |     15 |   17 |      12 |   17 |
|  8 |   13 |     19 |   13 |      13 |   13 |
|  8 |   13 |     19 |   13 |      15 |   13 |
| 13 |   20 |      5 |   20 |      16 |   20 |
| 17 |   20 |      5 |   20 |      16 |   20 |
| 10 |   17 |      2 |   17 |      19 |   17 |
| 20 |   17 |      2 |   17 |      19 |   17 |
| 10 |   17 |     15 |   17 |      19 |   17 |
| 20 |   17 |     15 |   17 |      19 |   17 |
| 10 |   17 |      2 |   17 |      20 |   17 |
| 20 |   17 |      2 |   17 |      20 |   17 |
| 10 |   17 |     15 |   17 |      20 |   17 |
| 20 |   17 |     15 |   17 |      20 |   17 |
|  5 |   10 |      1 |   10 |    NULL | NULL |
|  1 |   16 |      3 |   16 |    NULL | NULL |
|  5 |   10 |      4 |   10 |    NULL | NULL |
|  4 |    1 |      7 |    1 |    NULL | NULL |
| 19 |   11 |     10 |   11 |    NULL | NULL |
| 19 |   11 |     12 |   11 |    NULL | NULL |
|  4 |    1 |     13 |    1 |    NULL | NULL |
|  6 |    7 |     16 |    7 |    NULL | NULL |
| 18 |    7 |     16 |    7 |    NULL | NULL |
|  9 |   15 |   NULL | NULL |    NULL | NULL |
| 11 |   19 |   NULL | NULL |    NULL | NULL |
| 15 |   19 |   NULL | NULL |    NULL | NULL |
+----+------+--------+------+---------+------+
51 rows in set (0.00 sec)

3 没优化前

查询效率很差,需要优化

mysql> explain select * from class LEFT JOIN book on class.card = book.card LEFT JOIN phone on book.card = phone.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) |
|  1 | SIMPLE      | phone | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

4 建立索引进行优化

mysql> alter table phone add index z(card);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table book add index z(card);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

5 优化后的效果

mysql> explain select * from class LEFT JOIN book on class.card = book.card LEFT JOIN phone on book.card = phone.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  | z             | z    | 4       | db01.class.card |    1 |   100.00 | Using index |
|  1 | SIMPLE      | phone | NULL       | ref  | z             | z    | 4       | db01.book.card  |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------+---------+-----------------+------+----------+-------------+

后两行的 type 都是 ref 且总 rows 优化很好,效果不错。因此索引最好建立在需要经常查询的字段中。

三 小结

尽可能减少 join 语句中嵌套的循环总次数,永远用小结果集驱动大的结果集。即小表驱动大表。(书多于类别,书是大表,类别是小表,类别驱动书)

优先优化嵌套循环中的内层循环。

保证 join 语句中被驱动表上 join 条件字段已经被索引。(被驱动的表为 book 和 phone,给它们对应的条件字段 card 建立索引)

当无法保证被驱动表的 Join 条件字段被索引且内层资源充足的前提下,不要太吝啬 JoinBuffer 的设置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值