EXPLAIN sql优化方法(3)DERIVED
派生表和視圖的性能
從MySQL 4.1開始,它已經支持派生表、聯機視圖或者基本的FROM從句的子查詢。
這些特性之間彼此相關,但是它們之間的性能比較如何呢?
MySQL 5.0 中的派生表似乎和視圖實現的方式不同,盡管我從合并的代碼基數來看覺得在查詢優化上應該是一樣的。
派生表仍然以臨時表的方式顯式地處理,而且還是沒有索引的臨時表(因此最好不要像在例子中那樣連接2個派生表)
需要考慮的另一方面是,派生表需要被顯式處理,盡管只是執行 EXPLAIN 語句。因此如果在 FROM 字句中的 SELELCT 操作上犯了錯誤,例如忘記了寫上連接的條件,那么 EXPLAIN 可能會一直在運行。
視圖則不同,它無需被顯式處理,只是把查詢簡單地重寫了一下。只有在無法合并查詢或者試圖創建者請求時才需要被顯式處理。
這意味著它們在性能上的差別如下:
在基本的表上執行有索引 的查詢,這非常快
Java代碼 mysql>SELECT*FROMtestWHEREi=5;+---+----------------------------------+|i|j|+---+----------------------------------+|5|0c88dedb358cd96c9069b73a57682a45|+---+----------------------------------+1rowINSET(0.03sec)
mysql> SELECT * FROM test WHERE i=5 ; +---+----------------------------------+ | i | j | +---+----------------------------------+ | 5 | 0c88dedb358cd96c9069b73a57682a45 | +---+----------------------------------+ 1 row IN SET ( 0 .03 sec)
在派生表上做同樣的查詢,則如老牛拉破車
Java代碼 mysql>SELECT*FROM(SELECT*FROMtest)tWHEREi=5;+---+----------------------------------+|i|j|+---+----------------------------------+|5|0c88dedb358cd96c9069b73a57682a45|+---+----------------------------------+1rowINSET(1min40.86sec)
mysql> SELECT * FROM ( SELECT * FROM test) t WHERE i=5 ; +---+----------------------------------+ | i | j | +---+----------------------------------+ | 5 | 0c88dedb358cd96c9069b73a57682a45 | +---+----------------------------------+ 1 row IN SET ( 1 min 40 .86 sec)
在視圖上查詢,又快起來了
Java代碼 mysql>CREATEVIEWvASSELECT*FROMtest;QueryOK,0rowsaffected(0.08sec)mysql>SELECT*FROMvWHEREi=5;+---+----------------------------------+|i|j|+---+----------------------------------+|5|0c88dedb358cd96c9069b73a57682a45|+---+----------------------------------+1rowINSET(0.10sec)
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結果也許會讓你很驚訝
Java代碼 mysql>EXPLAINSELECT*FROMvWHEREi=5;+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+|id|select_type|TABLE|type|possible_keys|KEY|key_len|ref|rows|Extra|+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+|1|PRIMARY|test|const|PRIMARY|PRIMARY|4|const|1||+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+1rowINSET(0.02sec)mysql>EXPLAINSELECT*FROM(SELECT*FROMtest)tWHEREi=5;+----+-------------+------------+------+---------------+------+---------+------+---------+-------------+|id|select_type|TABLE|type|possible_keys|KEY|key_len|ref|rows|Extra|+----+-------------+------------+------+---------------+------+---------+------+---------+-------------+|1|PRIMARY|<derived2>|ALL|NULL|NULL|NULL|NULL|1638400|USINGWHERE||2|DERIVED|test|ALL|NULL|NULL|NULL|NULL|1638400||+----+-------------+------------+------+---------------+------+---------+------+---------+-------------+2rowsINSET(54.90sec)
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 子句中使用到子查詢,可以考慮在查詢時創建試圖,當查詢完之后刪除試圖。
不適合多表視圖,多表時用派生表取代視圖
Java代碼 explainselectsum(pdm.qty)pre_total,pd.pre_doc_idfromprepare_docpdleftjoinpre_doc_itempdmonpd.pre_doc_id=pdm.pre_doc_idgroupbypd.pre_doc_id
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
原文地址:http://hudeyong926.iteye.com/blog/785188
總結
以上是生活随笔為你收集整理的EXPLAIN sql优化方法(3)DERIVED的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 清华大学全固态锂电池新突破:迄今为止循环
- 下一篇: WPS被曝删除用户文件!金山办公回应:讹