EXPLAIN sql優化方法3 DERIVED 派生表
派生表和檢視的效能
從MySQL 4.1開始,它已經支援派生表、聯機檢視或者基本的FROM從句的子查詢。
這些特性之間彼此相關,但是它們之間的效能比較如何呢?
MySQL 5.0 中的派生表似乎和檢視實現的方式不同,儘管我從合併的程式碼基數來看覺得在查詢優化上應該是一樣的。
派生表仍然以臨時表的方式顯式地處理,而且還是沒有索引的臨時表(因此最好不要像在例子中那樣連線2個派生表)
需要考慮的另一方面是,派生表需要被顯式處理,儘管只是執行 EXPLAIN 語句。因此如果在 FROM 字句中的 SELELCT 操作上犯了錯誤,例如忘記了寫上連線的條件,那麼 EXPLAIN 可能會一直在執行。
檢視則不同,它無需被顯式處理,只是把查詢簡單地重寫了一下。只有在無法合併查詢或者試圖建立者請求時才需要被顯式處理。
這意味著它們在效能上的差別如下:
在基本的表 上執行有索引 的查詢,這非常快
- mysql> SELECT * FROM test WHERE i=5 ;
- +---+----------------------------------+
- | i | j |
- +---+----------------------------------+
-
| 5 | 0c88dedb358cd96c9069b73a57682a45 |
- +---+----------------------------------+
- 1 row IN SET ( 0 .03 sec)
在派生表 上做同樣 的查詢,則如老牛拉破車
- mysql> SELECT * FROM ( SELECT * FROM test) t WHERE i=5 ;
- +---+----------------------------------+
- | i | j |
- +---+----------------------------------+
-
| 5 | 0c88dedb358cd96c9069b73a57682a45 |
- +---+----------------------------------+
- 1 row IN SET ( 1 min 40 .86 sec)
在檢視 上查詢,又快起來了
- mysql> CREATE VIEW v AS SELECT * FROM test;
- Query OK, 0 rows affected ( 0 .08 sec)
- mysql> SELECT * FROM v WHERE i=5 ;
- +---+----------------------------------+
- | i | j |
- +---+----------------------------------+
- | 5 | 0c88dedb358cd96c9069b73a57682a45 |
- +---+----------------------------------+
- 1 row IN SET ( 0 .10 sec)
下面的2條EXPLAIN結果也許會讓你很驚訝
- mysql> EXPLAIN SELECT * FROM v WHERE i=5 ;
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
- | id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
- | 1 | PRIMARY | test | const | PRIMARY | PRIMARY | 4 | const | 1 | |
- +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
- 1 row IN SET ( 0 .02 sec)
- mysql> EXPLAIN SELECT * FROM ( SELECT * FROM test) t WHERE i=5 ;
- +----+-------------+------------+------+---------------+------+---------+------+---------+-------------+
- | id | select_type | TABLE | type | possible_keys | KEY | key_len | ref | rows | Extra |
- +----+-------------+------------+------+---------------+------+---------+------+---------+-------------+
- | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL| 1638400 | USING WHERE |
- | 2 | DERIVED | test | ALL | NULL | NULL | NULL | NULL| 1638400 | |
- +----+-------------+------------+------+---------------+------+---------+------+---------+-------------+
- 2 rows IN SET ( 54 .90 sec)
避免使用派生表 -- 如果可能,最好採用其他方式來編寫查詢語句,大部分情況都比派生表來的快。很多情況下,甚至連獨立的臨時表都來的快,因為可以適當增加索引。
可以考慮使用臨時試圖來取代派生表 如果確實需要在 FROM 子句中使用到子查詢,可以考慮在查詢時建立試圖,當查詢完之後刪除試圖。
不適合多表檢視,多表時用派生表 取代 檢視
explain select sum(pdm.qty) pre_total,pd.pre_doc_id from prepare_doc pd
left join pre_doc_item pdm on pd.pre_doc_id=pdm.pre_doc_id group by pd.pre_doc_id