2016-07-07 59 views
2

什麼是SELECT * FROM Table的性能損失VS SELECT * FROM (SELECT * FROM Table AS A) AS B性能損失嵌套的MySQL查詢

我的問題是:首先,它的SELECT *參與過在表中的行重複,或將它簡單地返回所有行作爲沒有任何迭代的塊(因爲沒有給出WHERE子句),如果是這樣,示例2中的嵌套查詢涉及在表上迭代兩次,並且會花費兩倍於第一個查詢的時間?謝謝...

回答

2

這個問題的答案取決於你是否在5.7或5.7之前使用mysql。我可能會稍微改變你的問題,但希望下面的內容能夠捕捉到你的想法。

SELECT * FROM Table確實通過聚集索引的表掃描(物理排序)。在沒有主鍵的情況下,引擎可以使用implicitly。你說的沒有where子句。沒有嘗試過濾或選擇其他索引。

Explain輸出(參見also)示出了其簡要1行。這是相當直接的。解釋輸出和表格B的派生表格的性能會因5.7版本還是5.7版本之後的版本而異。

文檔Derived Tables in MySQL 5.7很好地描述了版本5.6和5.7,其中後者將不會因爲將物化派生表輸出中的變化併入外部查詢而提供懲罰。在以前的版本中,大量的開銷與派生的臨時表一起忍受。

在5.7之前測試性能損失相當容易。所需要的只是一箇中等規模的表格,以查看您的問題派生表對影響性能的顯着影響。下面的例子是在一個小桌子在5.6版本:

explain 
select qm1.title 
from questions_mysql qm1 
join questions_mysql qm2 
on qm2.qid<qm1.qid 
where qm1.qid>3333 and qm1.status='O'; 
+----+-------------+-------+-------+-----------------+---------+---------+------+-------+------------------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra           | 
+----+-------------+-------+-------+-----------------+---------+---------+------+-------+------------------------------------------------+ 
| 1 | SIMPLE  | qm1 | range | PRIMARY,cactus1 | PRIMARY | 4  | NULL | 5441 | Using where         | 
| 1 | SIMPLE  | qm2 | ALL | PRIMARY,cactus1 | NULL | NULL | NULL | 10882 | Range checked for each record (index map: 0x3) | 
+----+-------------+-------+-------+-----------------+---------+---------+------+-------+------------------------------------------------+ 


explain 
select b.title from 
( select qid,title from questions_mysql where qid>3333 and status='O' 
) b 
join questions_mysql qm2 
on qm2.qid<b.qid; 
+----+-------------+-----------------+-------+-----------------+---------+---------+------+-------+----------------------------------------------------+ 
| id | select_type | table   | type | possible_keys | key  | key_len | ref | rows | Extra            | 
+----+-------------+-----------------+-------+-----------------+---------+---------+------+-------+----------------------------------------------------+ 
| 1 | PRIMARY  | qm2    | index | PRIMARY,cactus1 | cactus1 | 10  | NULL | 10882 | Using index          | 
| 1 | PRIMARY  | <derived2>  | ALL | NULL   | NULL | NULL | NULL | 5441 | Using where; Using join buffer (Block Nested Loop) | 
| 2 | DERIVED  | questions_mysql | range | PRIMARY,cactus1 | PRIMARY | 4  | NULL | 5441 | Using where          | 
+----+-------------+-----------------+-------+-----------------+---------+---------+------+-------+----------------------------------------------------+ 

注意,我沒有改變的問題,但它之前說明5.7派生表和缺乏指標的使用與優化在版本的影響。派生表可以從索引中受益,因爲它正在實現。但此後它可以作爲臨時表使用,並且可以在不使用索引的情況下合併到外部查詢中。版本5.7中不是這種情況

+0

很好的解釋:) –

+0

關於性能問題,在兩個子查詢之間的連接操作中,是否最好在內部查詢中而不是外部查詢中指定LIMIT子句? ((SELECT ID FROM Table1 LIMIT 10)AS A NATURAL JOIN Table2))'會比'更好((SELECT id FROM Table1)AS A NATURAL JOIN Table2))LIMIT 10'(這可能包含一些語法錯誤,與表命名的關係,但...)?謝謝:) –

+0

最好在你的服務器版本,你的架構上玩它。以下是[5.6](http://i.imgur.com/jxsrvB2.jpg),位於非服務器級的筆記本電腦上。請注意,我從不使用自然連接。我儘量不要做廣泛的筆畫筆觸的答案。特別是在「解釋」輸出看起來相同。這在堆棧上發生得太多了。相反,將查詢指向更大的數據集,並對我們性能最差的查詢或一般調查執行至少15分鐘的測試,例如[here](http://stackoverflow.com/a/38189113)。性能會根據Optimizer的版本而有所不同。 – Drew