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

相關文章
相關標籤/搜索