2017-09-15 57 views
0

爲什麼MySQL工作臺告訴我說:mysql的執行計劃成本降低,訂單由?

SELECT * FROM file_results WHERE filter2_dec > 20 LIMIT 3 

比更高的成本:

SELECT * FROM file_results WHERE filter2_dec > 20 ORDER BY filter2_dec DESC LIMIT 3 

enter image description here

enter image description here

+0

這是根據實際運行時間還是估算成本計算的? –

回答

1

它很可能是因爲通過查詢你的訂單已指定它爲DESC。這很容易找到,因爲數據已經排序。而在你的其他說法,它仍然有通過每一個要運行的條目,然後限制爲前3名。

順序由是減少,因爲你該條款後限制。數據已經排序,因此更容易顯示結果。而更昂貴的聲明必須自己做,然後限制。這也將受到索引,數據庫管理系統的影響,並可能在實際的現場環境中表現不同。

+0

當我刪除desc時,我得到的order by語句的成本相同。 – Chris

0

可能是cos filter2_dec got on是結構列的索引。但是,如果你需要一些好的分析師,我認爲你必須過去有關表結構利用發動機...關心

0

我猜以下。

在第一個查詢中,filter2_dec > 20不是很有選擇性。所以,MySQL說:「我將要選擇很多行,所以我只做一個全表掃描」。這可能是由LIMIT增強的,因爲如果這些值是隨機存儲在行中的,它可能會很快達到3。根據WHERE條款的選擇性拒絕使用索引的選擇。

在第二查詢中,ORDER BY保持使用所述索引作爲可能性的選擇。如果引擎執行全表掃描,則需要對所有數據進行排序。相反,使用索引更有意義 - 最終會成爲整體節省。

換句話說,所述WHERE子句的選擇性拒絕指數被認爲是成本之前使用索引的。在第二種情況下,該選項因ORDER BY而保持打開狀態。

這是猜測,但它會解釋你所看到的。優化器很難。

+0

執行計劃表示,它使用索引範圍掃描來掃描兩者,而不是全掃描表:( – Chris

+0

@Chris ...。您會注意到'ORDER BY'在第二個計劃中沒有成本。在兩個查詢中,範圍掃描的估計值是不同的。 –

1

這與MySQL(當前)優化limit的方式有關。它基本上計算查詢就好像沒有限制,然後對查詢計劃進行一些調整以確認它可能會產生影響。

這會產生無法真正信任成本價值的副作用 - 如果您可以信任它:它的絕對值沒有多大意義,重要的是它低於所有其他執行計劃。

理論

首先,請不說,成本價值並不認爲你行的實際數量。你可以例如增加極限值,並且它不會改變絕對成本(直到它切換到不同的執行計劃)。

使用索引檢索3行顯然是一個不錯的選擇。這就是爲什麼兩個查詢都是這樣使用的。但是使用(不覆蓋)索引需要查找表以檢索其他列的值(select *)。它將讀取索引,然後從表中讀取一行,然後從索引讀取下一個條目,然後從表中讀取下一行。在某些時候,讀取整個表格(「全表掃描」)顯然會變得更快,並丟棄不需要的行而不是使用索引。

如果你對數據進行排序,這點是後話比如果你沒有事後對數據進行排序。

如果您不使用limit,MySQL將通過查看filter2_dec > 20並猜測它將獲得多少行來決定是否達到該點。嘗試在沒有limit的情況下執行您的查詢。它將使用全表掃描(否則使用比20更小的數字)。

現在增加值20,仍然無極限,以足夠高的,所以你只能得到一些行(但大於0)的值;我們假設這個值是1000

現在很棘手的部分:如果您添加limit,那麼該點(最好使用範圍掃描而不是表掃描)的值將會發生改變。

MySQL將嘗試通過在所有可能的執行計劃列表中進行一些修改來包含limit的影響,如同沒有限制一樣生成所有可能的執行計劃。例如。扔掉其中一些或基於它們添加修改後的副本。這可能會導致成本的奇怪值(因爲它們實際上不是該操作的成本,而是原始計劃的成本)。

實踐

讓我們來看看這個動作。因爲它取決於確切的優化器和mysql版本,所以你的實際行爲可能會有所不同。但對於這個簡單的查詢,它應該仍然保持一般。我會認爲SELECT * FROM file_results WHERE filter2_dec > 20將使用全表掃描,SELECT * FROM file_results WHERE filter2_dec > 1000將使用索引它自己(而實際上將返回一些行)。如果沒有,請調整該值或添加更多行(也可以運行optimize table)。

首先,請嘗試以下兩個查詢:

SELECT * FROM file_results WHERE filter2_dec > 20 
order by filter2_dec 

SELECT * FROM file_results WHERE filter2_dec > 20 
order by filter2_dec limit 10 

應顯示爲第一步相同的成本,但是這將是一個「全表掃描」第一個,和「指數範圍掃描「爲另一個。

limit基本上採取了原來的計劃,並用「索引範圍掃描」替換了「全表掃描」,但它無法計算新的成本。 MySQL只是「知道」,由於限制,全表掃描使用起來會很荒謬,並將其改爲範圍掃描。 「順序」本身不再花費任何東西。

現在檢查以下3個疑問:

SELECT * FROM file_results WHERE filter2_dec > 20 

SELECT * FROM file_results force index (file_results_filter2_dec_index) 
WHERE filter2_dec > 20 

SELECT * FROM file_results WHERE filter2_dec > 20 limit 10 

第2和第3應該具有相同的成本,而第一個要便宜一些 - 但得到了由limit - 操作拋出,所以第二次(和第三)現在是執行查詢最便宜的方式(你可以從字面上採取這樣的:limit強迫你使用索引,因爲一切將只是愚蠢)。最後,這就是您的查詢看起來比另一個更昂貴的原因。它基於不同的計劃。

最後一個檢查:

SELECT * FROM file_results WHERE filter2_dec > 1000 
order by filter2_dec 

SELECT * FROM file_results WHERE filter2_dec > 1000 
order by filter2_dec limit 10 

SELECT * FROM file_results WHERE filter2_dec > 1000 limit 10 

都應該表現出相同的執行計劃和相同的費用(有或沒有限制)。該計劃將自行選擇,即使沒有限制。 limit -optimizer所做的調整不需要這些計劃,只需要開始時更昂貴的計劃。