2008-11-22 121 views
1

注意:原始問題沒有實際意義,但掃描到底部以獲取相關內容。如何優化MySQL的常量查詢?

我有一個查詢我想優化,看起來是這樣的:

select cols from tbl where col = "some run time value" limit 1; 

我想知道正在使用哪些密鑰,但無論我傳遞給解釋一下,它能夠優化where子句(「不可能在哪裏注意到...」),因爲我給它一個常量。

  • 有沒有辦法告訴mysql不要在解釋中做不斷的優化?
  • 我錯過了什麼嗎?
  • 有沒有更好的方式來獲取我需要的信息?

編輯:EXPLAIN似乎給我的查詢計劃,將產生於常數值。由於查詢是存儲過程的一部分(並且在被調用之前生成了spoc中的IIRC查詢計劃),這對我沒有好處,因爲該值不是恆定的。我想要的是找出當優化器不知道實際值是什麼時將生成的查詢計劃。

我錯過了嗎?

Edit2:在其他地方問一下,似乎MySQL總是重新生成查詢計劃,除非你不想讓它重新使用它們。即使在存儲過程中。從這看來,我的問題似乎沒有實際意義。

但是,這並不使我真正想知道的實際意義:如何優化包含任何特定的查詢中是恆定的,但在那裏我,程序員,事先不知道值查詢什麼價值將被使用? - 例如,假設我的客戶端代碼正在使用where子句中的數字生成查詢。在某些情況下,該號碼將導致不可能在其他時間條款不會。我如何使用解釋來檢查查詢的優化程度?

我現在看到的最好的方法就是運行EXPLAIN上的存在/不存在案例的完整矩陣。真的,這不是一個很好的解決方案,因爲這很難,也很容易出錯。

回答

4

例如,說我的客戶端代碼正在生成一個查詢,其中有where子句中的數字。

有些時候這個數字會導致一個不可能的where子句其他時間不會。

如何使用解釋來檢查查詢的優化程度?

MySQL爲不同的綁定參數值構建不同的查詢計劃。

在此article你可以閱讀的時候做的MySQL優化做什麼的清單:

 
    Action          When 

    Query parse         PREPARE 
    Negation elimination      PREPARE 
    Subquery re-writes       PREPARE 

    Nested JOIN simplification     First EXECUTE 
    OUTER->INNER JOIN conversions    First EXECUTE 

    Partition pruning       Every EXECUTE 
    COUNT/MIN/MAX elimination     Every EXECUTE 
    Constant subexpression removal    Every EXECUTE 
    Equality propagation      Every EXECUTE 
    Constant table detection     Every EXECUTE 
    ref access analysis       Every EXECUTE 
    range/index_merge analysis and optimization Every EXECUTE 
    Join optimization       Every EXECUTE 

有一件事在此列表中缺少。

MySQL可以JOIN迭代重建查詢計劃:這樣一個被稱爲range checking for each record

如果你有一個表上的複合索引:這樣

CREATE INDEX ix_table2_col1_col2 ON table2 (col1, col2) 

和查詢:

SELECT * 
FROM table1 t1 
JOIN table2 t2 
ON  t2.col1 = t1.value1 
     AND t2.col2 BETWEEN t1.value2_lowerbound AND t2.value2_upperbound 

MySQL不會使用從(t1.value1, t1.value2_lowerbound)(t1.value1, t1.value2_upperbound)指數RANGE訪問。相反,它將使用(t1.value)上的索引REF訪問權限,並僅過濾出錯誤的值。

但是,如果你重寫本查詢:

SELECT * 
FROM table1 t1 
JOIN table2 t2 
ON  t2.col1 <= t1.value1 
     AND t2.col1 >= t2.value1 
     AND t2.col2 BETWEEN t1.value2_lowerbound AND t2.value2_upperbound 

,然後MySQL複檢將每個記錄索引RANGE訪問table1,並決定是否使用上飛RANGE訪問。

您可以在我的博客,這些文章讀到它:

所有這些事情都採用RANGE CHECKING FOR EACH RECORD

回到你的問題:沒有辦法知道哪些計劃將MySQL利用每一個給定的常量,因爲沒有計劃在給定常數之前。

不幸的是,沒有辦法強制MySQL爲綁定參數的每個值使用一個查詢計劃。

,可以控制通過使用STRAIGHT_JOINFORCE INDEX子句所選用的JOIN順序和INDEX「ES,但它們不會強迫上索引的某些訪問路徑或禁止IMPOSSIBLE WHERE

另一方面,對於所有JOIN's,MySQL只僱用NESTED LOOPS。這意味着如果您訂購JOIN訂單或選擇正確的索引,MySQL可能會受益於所有IMPOSSIBLE WHERE的。

5

由於您指定的值不在列中,而不僅僅是因爲它是一個常量,所以您會收到「不可能的WHERE注意事項」。你可以:1)使用該列中存在或值2)只是說col = col

explain select cols from tbl where col = col; 
+0

那些幽冥解決了我的問題。我想知道查詢計劃是優化器*不知道的地方*如果值在列中。 – BCS 2008-11-23 03:01:28

+0

下面是它的工作原理:優化器通過讀取const和系統表來確定選擇是否可能,如果是,則獲取查詢計劃。我的解決方案將爲您提供查詢計劃,因爲優化程序不會提前停止,因爲它認爲查詢是不可能的。 – 2008-11-23 03:28:24

+0

是的,它會給你一個查詢計劃並避免where子句永不傳遞的問題,但是它會假設where子句將總是*傳遞,而且也不是這種情況。我想要的是知道事情將如何執行這兩種情況。 (見編輯2) – BCS 2008-11-23 21:19:28

0

如何優化查詢與價值,只有到查詢是恆定的,但在那裏我,程序員,事先不知道將使用什麼價值?

通過使用特定列上的索引(或者如果您總是一起查詢給定的列,甚至可以組合列)。如果您有索引,查詢計劃員可能會使用它們。

關於「不可能」的數值:查詢規劃可以得出結論,一個給定的值不在表從幾個來源:

  • 如果有特定的列的索引,其可以觀察到特定值大於或小於索引中的任何值(最小/最大值需要從索引中抽取一段時間)
  • 如果傳入的類型錯誤(如果要求數字列與文本相等)

PS。一般來說,查詢計劃的創建並不昂貴,重新創建比重新使用它更好,因爲自查詢計劃生成並且可能存在更好的查詢計劃以來,條件可能已發生變化。