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),效率必然低下。

所以,當對連接屬性進行排序時,應當選擇驅動表的屬性作為排序表中的條件。

    -- 對被驅動表字段進行排序
    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]。

首先我們找出驅動表和被驅動表,按照小表驅動大表的原則,大表是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原理的基礎上進行優化的手段。希望對大家有幫助吧:)

MySQL的JOIN(一):用法

MySQL的JOIN(二):JOIN原理

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

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM