2012-04-13 47 views
19

的MySQL查詢望着查詢的EXPLAIN計劃,一個人如何確定在何處的優化才能最好地做出?如何優化基於解釋計劃

我意識到的第一件事情要檢查一個是是否正在使用良好的指標,但除此之外,我有點爲難。通過過去的嘗試和錯誤,我有時會發現,進行連接的順序可能是一個很好的改進來源,但是如何通過查看執行計劃來確定?

雖然我非常希望獲得對如何優化查詢的好大致的瞭解(建議閱讀非常感謝!),我也認識到,它往往更容易討論比抽象的談具體案例。由於我目前撞我的頭這一個牆,您的想法將是非常讚賞:

 
id select_type table type  possible_keys key  key_len ref     rows Extra 
1 SIMPLE  S  const PRIMARY,l,p,f4 PRIMARY   2 const      1 Using temporary 
1 SIMPLE  Q  ref  PRIMARY,S  S    2 const     204 Using index 
1 SIMPLE  V  ref  PRIMARY,n,Q  Q    5 const,db.Q.QID   6 Using where; Using index; Distinct 
1 SIMPLE  R1  ref  PRIMARY,L  L    154 const,db.V.VID   447 Using index; Distinct 
1 SIMPLE  W  eq_ref PRIMARY,w  PRIMARY   5 const,db.R.RID,const  1 Using where; Distinct 
1 SIMPLE  R2  eq_ref PRIMARY,L  PRIMARY  156 const,db.W.RID,const  1 Using where; Distinct 

上午我在解釋執行計劃的最後一行更正如下:

  • 爲它的主鍵完全匹配,每個輸出行只需要獲取一行R2;
  • 然而,這樣的輸出行然後基於應用於R2某些標準過濾?

如果是這樣,我的問題在於最後一步發生的過濾。如果條件不進行過濾(例如WHERE `Col_1_to_3` IN (1,2,3)),則查詢運行速度非常快(〜50ms)。但是,如果條件限制所選的行(WHERE `Col_1_to_3` IN (1,2)),則查詢需要相當長的時間(〜5秒)。如果限制爲單一匹配(WHERE `Col_1_to_3` IN (1)),優化器會提出一個完全不同的執行計劃(其執行效果略好於5s,但仍比50ms差很多)。看起來好像沒有更好的索引可以用於該表(因爲它已經完全使用主鍵來爲每個結果返回一行)。

一個應該如何解讀這些信息?我是否猜測,因爲這樣的輸出過濾發生在要加入的最終表上,相對於之前加入表格並過早過濾這些行而言,會付出相當大的努力呢?如果是這樣,如何確定執行計劃R2何時應該加入?

雖然我拒絕了,包括在這裏充分查詢&架構(如我真的很容易知道該找什麼,而不是僅僅被告知的答案),我明白有必要提前討論:

SELECT DISTINCT 
    `Q`.`QID` 
FROM 
    `S` 
    NATURAL JOIN `Q` 
    NATURAL JOIN `V` 
    NATURAL JOIN `R` AS `R1` 
    NATURAL JOIN `W` 

    JOIN `R` AS `R2` ON (
      `R2`.`SID` = `S`.`SID` 
     AND `R2`.`RID` = `R1`.`RID` 
     AND `R2`.`VID` = `S`.`V_id` 
     AND `R2`.`Col_1_to_3` IN (1,2) -- this is where performance suffers! 
    ) 

WHERE 
    AND `S`.`SID` = @x 
    AND `W`.`WID` = @y 
; 

R的定義是:

CREATE TABLE `R` (
    `SID` smallint(6) unsigned NOT NULL, 
    `RID` smallint(6) unsigned NOT NULL, 
    `VID` varchar(50) NOT NULL DEFAULT '', 
    `Col_1_to_3` smallint(1) DEFAULT NULL, 
    `T` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`SID`,`RID`,`VID`), 
    KEY `L` (`SID`,`VID`,`Col_1_to_3`), 
    CONSTRAINT `R_f1` FOREIGN KEY (`SID`) REFERENCES `S` (`SID`), 
    CONSTRAINT `R_f2` FOREIGN KEY (`SID`, `VID`) REFERENCES `V` (`SID`, `VID`), 
    CONSTRAINT `R_f3` FOREIGN KEY (`SID`, `VID`, `Col_1_to_3`) REFERENCES `L` (`SID`, `VID`, `LID`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
+0

你介意顯示查詢嗎? – 2012-04-13 22:04:31

+0

@MarcusAdams:我不介意*,但你會找什麼?我覺得如果我知道你會看到什麼,我可能會學到更多... – eggyal 2012-04-13 22:07:53

+0

你指的是col_1_to_3,但我在EXPLAIN結果中看不到這樣的列。如果您可以對問題進行短語說明,只是說明問題,換句話說,刪除討論查詢的段落,那麼我們不需要查詢,答案是肯定的。一般來說,我們需要查詢,模式和解釋,否則我們猜測。 – 2012-04-13 22:12:31

回答

13

取決於你要去的,什麼查詢是什麼。

通常,對於EXPLAIN中具有Using where的每一行,都需要使用索引(possible keyskeys列)。這些是你的過濾器,包括WHERE和ON。說它Using index更好。這意味着有一個覆蓋索引,MySQL可以從索引中檢索數據,而不是訪問表數據中的行。

那裏沒有Using where的線條,和它返回大量行的應該看。這些是表中所有行的返回值。我不知道你的問題是什麼,所以我不知道這裏是否會受到驚嚇。嘗試過濾結果集以縮小尺寸並提高性能。

你通常應該儘量避免看到Using filesortUsing temporary,儘管如果你不期待他們,那些只會是壞的。

Filesort通常與ORDER子句一起出現。您通常希望MySQL使用覆蓋索引(Using index),以便從服務器按順序返回行。如果它們不是,那麼MySQL必須使用filesort命令它們。

Using temporary由於沒有索引而引用派生表時可能會很糟糕。看起來你已經明確創建了一個帶有索引的臨時表,所以在這裏,這並不壞。有時,你唯一的選擇是使用派生表,因此Using temporary

+0

謝謝Marcus。我想我覺得最奇怪的是在決賽桌上的過濾器產生的顯着性能差異;因此,似乎這個問題不在「其中......正在返回大量行的行中」,您建議我看一下? – eggyal 2012-04-13 23:01:43