這篇博文講述如何優化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