爲什麼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
爲什麼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
它很可能是因爲通過查詢你的訂單已指定它爲DESC。這很容易找到,因爲數據已經排序。而在你的其他說法,它仍然有通過每一個要運行的條目,然後限制爲前3名。
順序由是減少,因爲你該條款後限制。數據已經排序,因此更容易顯示結果。而更昂貴的聲明必須自己做,然後限制。這也將受到索引,數據庫管理系統的影響,並可能在實際的現場環境中表現不同。
當我刪除desc時,我得到的order by語句的成本相同。 – Chris
可能是cos filter2_dec got on是結構列的索引。但是,如果你需要一些好的分析師,我認爲你必須過去有關表結構利用發動機...關心
我猜以下。
在第一個查詢中,filter2_dec > 20
不是很有選擇性。所以,MySQL說:「我將要選擇很多行,所以我只做一個全表掃描」。這可能是由LIMIT
增強的,因爲如果這些值是隨機存儲在行中的,它可能會很快達到3。根據WHERE
條款的選擇性拒絕使用索引的選擇。
在第二查詢中,ORDER BY
保持使用所述索引作爲可能性的選擇。如果引擎執行全表掃描,則需要對所有數據進行排序。相反,使用索引更有意義 - 最終會成爲整體節省。
換句話說,所述WHERE
子句的選擇性拒絕指數被認爲是成本之前使用索引的。在第二種情況下,該選項因ORDER BY
而保持打開狀態。
這是猜測,但它會解釋你所看到的。優化器很難。
執行計劃表示,它使用索引範圍掃描來掃描兩者,而不是全掃描表:( – Chris
@Chris ...。您會注意到'ORDER BY'在第二個計劃中沒有成本。在兩個查詢中,範圍掃描的估計值是不同的。 –
這與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所做的調整不需要這些計劃,只需要開始時更昂貴的計劃。
這是根據實際運行時間還是估算成本計算的? –