Mysql

決定哪個 MySQL 執行計劃更好

  • October 6, 2014

背景:

我有一個要加快速度的查詢,涉及 3 個表:

  • omgenvelope有 500 萬行
  • omgcust有 195 行
  • omginput有 35836 行

我正在獲取omginput某些 s 引用的 distinct somgenvelopeomgcust從屬於omginput.

到目前為止我的兩個查詢變體:

選擇客戶、客戶名稱、idomginput、文件名、omginput.laststamp
FROM omginput, omgcust
在哪裡 idomg 輸入
(從 omgenvelope 選擇 DISTINCT(lastinput)WHERE envstate NOT IN (42,46,65,70,250))
AND idomgcust=customer ORDER BY omginput.laststamp,文件名;

對比

SELECT DISTINCT 客戶、客戶名稱、idomginput、文件名、omginput.laststamp
來自 omgenvelope
加入 omginput ON(idomginput=lastinput AND envstate NOT IN (42,46,65,70,250))
加入 omgcust ON (idomgcust=customer) ORDER BY omginput.laststamp, filename;

查詢計劃:

EXPLAIN在上面的查詢中,帶有IN (SELECT...)子查詢,顯示了這個計劃(縮寫):

選擇類型:主要
表:omgcust
類型:全部
可能的鍵:主要
鍵:空
key_len:空
參考:空
行數:195
額外:使用臨時;使用文件排序
--------------
選擇類型:主要
表:omginput
類型:參考
鍵:fk_omginput_omgcust1_idx
關鍵長度:4
參考:tracksdb.omgcust.idomgcust
行數:109
額外:使用 where
--------------
選擇類型:相關子查詢
表:omgenvelope
類型:index_subquery
鍵:fk_omgenvelope_omginput1_idx
關鍵長度:4
參考:函式
行數:867
額外:使用 where

我正在考慮使用的新查詢:

選擇類型:簡單
表:omgenvelope
類型:範圍
鍵:fk_omgenvelope_omgstate1_idx
關鍵長度:4
參考:空
行數:886220
額外:使用where;使用臨時的;使用文件排序
--------------
選擇類型:簡單
表:omginput
類型:eq_ref
關鍵:主要
關鍵長度:4
參考:tracksdb.omgenvelope.lastinput
行數:1
--------------
選擇類型:簡單
表:omgcust
類型:eq_ref
關鍵:主要
關鍵長度:4
參考:tracksdb.omginput.customer
行數:1

題:

我如何量化哪一個更有效?舊的DEPENDENT SUBQUERY看起來很簡單,並且在每個步驟中不會產生這麼多行(195 * 109 * 867)。另一方面,新候選顯示 (886220 * 1 * 1) 行。

所以我的問題是如何解釋這些估計的行數。我可以將它們相乘並比較產品,還是我需要更多地考慮 RDBMS 在執行查詢時實際在做什麼?

由於以下幾個原因,將行相乘是無效的:

  • 很多時候,檢查的行是一個近似值(基於統計,不准確),有利於查詢計劃選擇,但不適用於性能計算
  • 在嵌套循環連接上檢查的總行數(A, B)不是rows_examined_on_table_A * rows_examined_on_table_B,而是rows_examined_on_table_A + rows_returned_from_table_A * rows_examined_on_table_B。Where 子句可以對此產生巨大的影響,儘管確實提到的計算多次被用作廣泛的近似值,假設索引被正確創建並且是過濾掉結果的主要原因。
  • 現代 MySQL 版本並不總是使用嵌套循環連接方法來執行連接和子查詢。查看5.6 子查詢優化和同一手冊上的其他優化文件。此外,一些新的優化技術不會修改預測的檢查行,即使它已經被精確計算,有時也可能低於列印的行。

特別是,在您的第一個查詢中,您遇到了一個眾所周知的 MySQL 錯誤?局限性?其中 IN 子查詢被標識為DEPENDENT SUBQUERY,即使它確實不是,強制最外層查詢在沒有索引(全表掃描)的情況下執行,以測試第一個表的所有可能值。這通常表明它是一個錯誤的查詢。在這種情況下似乎並不算太糟糕,因為表很小,但這通常表明性能不佳。

應該引起您注意的另一件事是Using temporary; Using filesort。過濾不是您應該關注的唯一事情,因為這些額外的資訊告訴您必須使用臨時表完成大型排序(可能會或可能不會最終在磁碟上,但至少必須實現)。這是潛在不良性能的另一個指標,在某些情況下可以通過正確的索引來避免。

我不會告訴你使用哪個查詢是正確的(部分原因是我不知道所有變數:索引、表結構等,並且在大多數情況下它取決於可用的特定硬體/資源),但我將告訴您決定的工具:

  • 分析查詢 - 獲取後執行時間以及其中投入了多少。您可以使用高達 5.5 的SHOW PROFILES ,以及從 5.6 開始的performance_schema 。
  • 由於時間有時是可變的(例如,取決於同時執行的其他查詢,取決於緩衝池的內容) 使用 獲取執行後統計資訊SHOW SESSION STATUS。特別是:
FLUSH SESSION STATUS;
SELECT ... ;
SHOW STATUS like 'Hand%';

將為您提供完成的處理程序呼叫的確切數量(大約,為該特定查詢讀取和寫入的行數 - 儘管這不是 100% 準確,因為它取決於特定的引擎實現)。

您可能還想監視其他狀態變數,例如創建的臨時表、磁碟上創建的臨時表和排序通過/排序的行。

所有這些都將為您提供執行後、準確、與時間無關的參數來評估查詢的性能。Percona 甚至為慢速日誌提供了一個更新檔,可以在日誌上輸出該資訊,而不是使用 performance_schema。

有了這些額外的資訊,您將能夠更客觀地評估哪個查詢更好,而不是完全依賴 EXPLAIN,它只提供有限的執行前資訊。

引用自:https://dba.stackexchange.com/questions/78450