MySQL的JOIN(四):JOIN优化实践之快速匹配

这篇博文讲述如何优化扫描速度。咱们经过MySQL的JOIN(二):JOIN原理得知了两张表的JOIN操做就是不断从驱动表中取出记录,而后查找出被驱动表中与之匹配的记录并链接。这个过程的实质就是查询操做,想要优化查询操做,建索引是最经常使用的方式。那索引怎么建呢?咱们来讨论下,首先插入测试数据。oop

 

CREATE TABLE t1 (
        id INT PRIMARY KEY AUTO_INCREMENT,
        type INT
    );
    SELECT COUNT(*) FROM t1;
    +----------+
    | COUNT(*) |
    +----------+
    |   110000 |
    +----------+
    CREATE TABLE t2 (
        id INT PRIMARY KEY AUTO_INCREMENT,
        type INT
    );
    SELECT COUNT(*) FROM t2;
    +----------+
    | COUNT(*) |
    +----------+
    |      100 |
    +----------+

 

左链接

左链接中,左表是驱动表,右表是被驱动表。想要快速查找被驱动表中匹配的记录,因此咱们能够在右表建索引,从而提升链接性能。性能

 

-- 首先两个表都没建索引
    EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.type=t2.type;
    +----+-------+------+------+--------+----------------------------------------------------+
    | id | table | type | key  | rows   | Extra                                              |
    +----+-------+------+------+--------+----------------------------------------------------+
    |  1 | t1    | ALL  | NULL | 110428 | NULL                                               |
    |  1 | t2    | ALL  | NULL |    100 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------+------+------+--------+----------------------------------------------------+

    -- 尝试在左表创建索引,改进不大
    CREATE INDEX idx_type ON t1(type);
    EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.type=t2.type;
    +----+-------+-------+----------+--------+----------------------------------------------------+
    | id | table | type  | key      | rows   | Extra                                              |
    +----+-------+-------+----------+--------+----------------------------------------------------+
    |  1 | t1    | index | idx_type | 110428 | Using index                                        |
    |  1 | t2    | ALL   | NULL     |    100 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------+-------+----------+--------+----------------------------------------------------+


    -- 尝试在右表创建索引,效果拔群,Using index!!!
    DROP INDEX idx_type ON t1;
    CREATE INDEX idx_type ON t2(type);
    EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.type=t2.type;
    +----+-------+------+---------------+----------+--------+-------------+
    | id | table | type | possible_keys | key      | rows   | Extra       |
    +----+-------+------+---------------+----------+--------+-------------+
    |  1 | t1    | ALL  | NULL          | NULL     | 110428 | NULL        |
    |  1 | t2    | ref  | idx_type      | idx_type |      1 | Using index |
    +----+-------+------+---------------+----------+--------+-------------+

 

右链接

右链接中,右表是驱动表,左表是被驱动表,想要快速查找被驱动表中匹配的记录,因此咱们能够在左表建索引,从而提升链接性能。测试

DROP INDEX idx_type ON t2;
    -- 两个表都没有索引
    EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.type=t2.type;
    +----+-------+------+------+--------+----------------------------------------------------+
    | id | table | type | key  | rows   | Extra                                              |
    +----+-------+------+------+--------+----------------------------------------------------+
    |  1 | t2    | ALL  | NULL |    100 | NULL                                               |
    |  1 | t1    | ALL  | NULL | 110428 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------+------+------+--------+----------------------------------------------------+


    -- 在右边创建索引,改进不大
    CREATE INDEX idx_type ON t2(type);
    EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.type=t2.type;
    +----+-------+-------+---------------+----------+--------+----------------------------------------------------+
    | id | table | type  | possible_keys | key      | rows   | Extra                                              |
    +----+-------+-------+---------------+----------+--------+----------------------------------------------------+
    |  1 | t2    | index | NULL          | idx_type |    100 | Using index                                        |
    |  1 | t1    | ALL   | NULL          | NULL     | 110428 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------+-------+---------------+----------+--------+----------------------------------------------------+


    -- 尝试在左边创建索引,效果拔群!
    DROP INDEX idx_type ON t2;
    CREATE INDEX idx_type ON t1(type);
    EXPLAIN SELECT * FROM t1 RIGHT JOIN t2 ON t1.type=t2.type;
    +----+-------+------+---------------+--------------+------+-------------+
    | id | table | type | possible_keys | ref          | rows | Extra       |
    +----+-------+------+---------------+--------------+------+-------------+
    |  1 | t2    | ALL  | NULL          | NULL         |  100 | NULL        |
    |  1 | t1    | ref  | idx_type      | test.t2.type |    5 | Using index |
    +----+-------+------+---------------+--------------+------+-------------+

内链接

咱们知道,MySQL Optimizer会对内链接作优化,无论谁内链接谁,都是用小表驱动大表,因此若是要优化内链接,能够在大表上创建索引,以提升链接性能。优化

另外注意一点,在小表上创建索引时,MySQL Optimizer会认为用大表驱动小表效率更快,转而用大表驱动小表。spa

对内链接小表驱动大表的优化策略不清楚的话,.net

能够看MySQL的JOIN(三):JOIN优化实践以内循环的次数blog

DROP INDEX idx_type ON t1;
    -- 两个表都没有索引,t2驱动t1
    EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.type=t2.type;
    +----+-------+------+------+--------+----------------------------------------------------+
    | id | table | type | key  | rows   | Extra                                              |
    +----+-------+------+------+--------+----------------------------------------------------+
    |  1 | t2    | ALL  | NULL |    100 | NULL                                               |
    |  1 | t1    | ALL  | NULL | 110428 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------+------+------+--------+----------------------------------------------------+

    -- 在t2表上创建索引,MySQL的Optimizer发现后,用大表驱动了小表
    CREATE INDEX idx_type ON t2(type);
    EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.type=t2.type;
    +----+-------+------+----------+--------+-------------+
    | id | table | type | key      | rows   | Extra       |
    +----+-------+------+----------+--------+-------------+
    |  1 | t1    | ALL  | NULL     | 110428 | Using where |
    |  1 | t2    | ref  | idx_type |      1 | Using index |
    +----+-------+------+----------+--------+-------------+


    -- 在t1表上创建索引,再加上t1是大表,符合“小表驱动大表”的原则,性能比上面的语句要好
    DROP INDEX idx_type ON t2;
    CREATE INDEX idx_type ON t1(type);
    EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.type=t2.type;
    +----+-------+------+---------------+----------+------+-------------+
    | id | table | type | possible_keys | key      | rows | Extra       |
    +----+-------+------+---------------+----------+------+-------------+
    |  1 | t2    | ALL  | NULL          | NULL     |  100 | Using where |
    |  1 | t1    | ref  | idx_type      | idx_type |    5 | Using index |
    +----+-------+------+---------------+----------+------+-------------+

 

三表链接

上面都是两表链接,三表链接也是同样的,找出驱动表和被驱动表,在被驱动表上创建索引,便可提升链接性能。索引

总结

想要从快速匹配的角度优化JOIN,首先就是找出谁是驱动表,谁是被驱动表,而后在被驱动表上创建索引便可。get

相关文章
相关标签/搜索