MySQL的JOIN(五):JOIN優化實踐之排序

這篇博文講述如何優化JOIN查詢帶有排序的狀況。大體分爲對鏈接屬性排序對非鏈接屬性排序兩種狀況。插入測試數據。算法

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

 

對鏈接屬性進行排序

現要求對t1和t2作內鏈接,鏈接條件是t1.id=t2.id,並對鏈接屬性id屬性進行排序(MySQL爲主鍵id創建了索引)。測試

有兩種選擇,方式一[...ORDER BY t1.id],方式二[...ORDER BY t2.id],選哪一種呢?優化

首先咱們找出驅動表和被驅動表,按照小表驅動大表的原則,大表是t1,小表是t2,因此t2是驅動表,t1是非驅動表,t2驅動t1。而後進行分析,若是咱們使用方式一的話,MySQL會先對t1進行排序而後執行錶鏈接算法,若是咱們使用方式二的話,只能執行錶鏈接算法後對結果集進行排序(extra:using temporary),效率必然低下。spa

因此,當對鏈接屬性進行排序時,應當選擇驅動表的屬性做爲排序表中的條件。.net

-- 對被驅動表字段進行排序
    EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.id =t2.id ORDER BY t1.id;
    +----+-------+--------+---------+------+---------------------------------+
    | id | table | type   | key     | rows | Extra                           |
    +----+-------+--------+---------+------+---------------------------------+
    |  1 | t2    | ALL    | NULL    |  100 | Using temporary; Using filesort |
    |  1 | t1    | eq_ref | PRIMARY |    1 | NULL                            |
    +----+-------+--------+---------+------+---------------------------------+


    -- 對驅動表字段進行排序,沒有Using temporary,也沒有Using filesort 
    EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.id =t2.id ORDER BY t2.id;
    +----+-------+--------+---------+------+-------+
    | id | table | type   | key     | rows | Extra |
    +----+-------+--------+---------+------+-------+
    |  1 | t2    | index  | PRIMARY |  100 | NULL  |
    |  1 | t1    | eq_ref | PRIMARY |    1 | NULL  |
    +----+-------+--------+---------+------+-------+

 

對非鏈接屬性進行排序

現要求對t1和t2作內鏈接,鏈接條件是t1.id=t2.id,並對非鏈接屬性t1的type屬性進行排序,[...ORDER BY t1.type]。blog

首先咱們找出驅動表和被驅動表,按照小表驅動大表的原則,大表是t1,小表是t2,因此MySQL Optimizer會用t2驅動t1。如今咱們要對t1的type屬性進行排序,t1是被驅動表,必然致使對鏈接後結果集進行排序Using temporary(比Using filesort更嚴重)。因此,能不能不用MySQL Optimizer,用大表驅動小表呢? 
有請STRAIGHT_JOIN!排序

EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.id =t2.id ORDER BY t1.type;
    +----+-------+--------+---------+------+---------------------------------+
    | id | table | type   | key     | rows | Extra                           |
    +----+-------+--------+---------+------+---------------------------------+
    |  1 | t2    | ALL    | NULL    |  100 | Using temporary; Using filesort |
    |  1 | t1    | eq_ref | PRIMARY |    1 | NULL                            |
    +----+-------+--------+---------+------+---------------------------------+


    -- Using temporary沒有了,可是大表驅動小表,致使內循環次數增長,實際開發中要從實際出發,
    -- 對此做出權衡。
    EXPLAIN SELECT * FROM t1 STRAIGHT_JOIN t2 ON t1.id =t2.id ORDER BY t1.type;
    +----+-------+--------+---------+-------+----------------+
    | id | table | type   | key     | rows  | Extra          |
    +----+-------+--------+---------+-------+----------------+
    |  1 | t1    | ALL    | NULL    | 10000 | Using filesort |
    |  1 | t2    | eq_ref | PRIMARY |     1 | NULL           |
    +----+-------+--------+---------+-------+----------------+

 

最後在MySQL的JOIN(一):用法那裏挖了個坑,如今填上:INNER JOIN、JOIN、WHERE等值鏈接和STRAIGHT_JOIN都能表示內鏈接,那平時如何選擇呢?通常狀況下用INNER JOIN、JOIN或者WHERE等值鏈接,由於MySQL Optimizer會按照「小表驅動大表的策略」進行優化。當出現上述問題時,才考慮用STRAIGHT_JOIN索引

總結

《MySQL的JOIN》到此爲止。開發

這系列博文講述了JOIN的用法,JOIN的原理,以及在JOIN原理的基礎上進行優化的手段。但願對你們有幫助吧:)get

MySQL的JOIN(一):用法

MySQL的JOIN(二):JOIN原理

MySQL的JOIN(三):JOIN優化實踐以內循環的次數

MySQL的JOIN(四):JOIN優化實踐之快速匹配

MySQL的JOIN(五):JOIN優化實踐之排序

相關文章
相關標籤/搜索