2016-03-15 35 views
0

我正在學習如何優化SQL語句,我想知道是否有可能通過查看執行來估計什麼可能會使查詢變慢計劃。只要看一眼的執行計劃是否有可能通過查看執行計劃來了解爲什麼我的查詢速度太慢

*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: <derived2> 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 382856 
     Extra: Using where; Using temporary; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: rf 
     type: ref 
possible_keys: rec_id 
      key: rec_id 
     key_len: 4 
      ref: rs.id 
     rows: 7 
     Extra: Using index condition 
*************************** 3. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: f 
     type: range 
possible_keys: facet_name_and_value,rec_id 
      key: facet_name_and_value 
     key_len: 309 
      ref: NULL 
     rows: 382856 
     Extra: Using index condition; Using where; Using temporary; Using filesort 
*************************** 4. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: r 
     type: ref 
possible_keys: record_id 
      key: record_id 
     key_len: 9 
      ref: sqlse_test_crescentbconflate.f.rec_id 
     rows: 1 
     Extra: Using where; Using index 

我可以看到,我使用了太多的連接和數據量太大,因爲SQL是使用文件排序,但我可能是錯的。

回答

1

不,這不是真的有可能從剛解釋輸出診斷性能問題。

但輸出也顯示,有是一個的返回(估計)384000行的視圖查詢。我們無法確定這是存儲視圖還是內聯視圖。但是我們可以看到,來自該查詢的結果正在物化爲一張表(MySQL稱之爲「派生表」),然後外部查詢正在運行。這種開銷可能相當大。

我們無法知道它是可以得到同樣的結果,而不認爲,扁平化查詢。如果這是不可能的,那麼外部查詢中是否有任何謂詞可以被推送到視圖中。

「使用filesort」不一定是壞事。但是,對於真正的大集合,該操作可能變得昂貴。所以我們希望避免不必要的排序操作。 (我們無法從EXPLAIN輸出中看出是否有可能避免這些排序操作。)

如果查詢使用「覆蓋索引」,則查詢從索引頁面滿足,而不需要在底層表中查找/訪問頁面,這意味着更少的工作要做。

此外,確保謂詞是在能夠有效地使用索引的一種形式。這意味着在裸列上有條件,而不是在函數中包裝列。例如

我們要避免寫這樣的條件:

where DATE_FORMAT(t.dt,'%Y-%m') = '2016-01' 

當一回事可以這樣表示:

where t.dt >= '2016-01-01' and t.dt < '2016-02-01' 

同前,MySQL有評價DATE_FORMAT功能表中的每一行,以及比較函數的返回值。對於後一種形式,MySQL可以對索引使用「範圍掃描」操作,其中dt作爲主要列。範圍掃描操作有可能非常有效地消除大量行,而無需實際檢查行。


總之,最大的性能改進,將有可能來自

  • 避免創建派生表(不視圖定義)
  • 推謂詞到視圖定義(其中視圖定義不能避免)
  • 避免不必要的排序操作
  • 避免不必要的連接
  • 個的形式編寫謂詞可以利用適當的索引
  • 創造合適的索引,覆蓋索引酌情
+0

只是要注意,這不是萬能的詳盡清單。這裏的建議在「SELECT」語句的性能方面進行了相當多的調查。但是這個答案並沒有涉及很多其他的性能調優主題:例如sql結果緩存,存儲引擎(MyISAM,InnoDB等)的差異,以及調整mysql實例本身(例如分配給InnoDB緩衝池的內存等) – spencer7593

1

我會查看執行計劃中的extra字段,然後檢查查詢和數據庫模式以找到提高性能的方法。

using temporary表示使用了臨時表,這可能會降低查詢速度。此外,臨時表可能最終會被寫入到磁盤(而不是存儲在RAM中,該服務器通常會嘗試做的,如果它可以),如果他們是太大。

根據MySQL 5.5 documentation,這裏有一些原因 臨時表的創建:

UNION語句
  • 評價。
  • 評價的一些視圖,例如那些使用不是Temptable算法,UNION,或聚集。
  • 評估包含ORDER BY子句和另一個GROUP BY子句的語句,或者ORDER BY或GROUP BY 包含來自隊列中第一個表以外的表的列。
  • 評價DISTINCT結合ORDER BY可能需要一個臨時表。
  • 對於使用SQL_SMALL_RESULT選項的查詢,MySQL使用內存中的臨時表,除非查詢還包含需要磁盤存儲的元素 (稍後介紹)。
  • 評價多表UPDATE語句。
  • GROUP_CONCAT的評價()或COUNT(DISTINCT)表達式。

再有就是using filesort,這意味着進行排序,其不能與現有的索引來完成。這可能是沒什麼大不了的,但你應該檢查哪些字段進行排序,並在您的索引,並確保你不給MySQL的太多的工作要做。

1

您可能可以使用執行計劃來了解爲什麼查詢運行緩慢,因爲您知道模式如何工作(您擁有哪些列和索引)。但是,我們這裏的Stack Overflow不可能僅僅使用執行計劃來幫助你。

filesort.沒有什麼內在錯誤它碰巧有一個不幸的名字;它只是意味着滿足查詢需要對子查詢的結果進行排序。這並不一定意味着子查詢的結果已放置在文件系統的實際文件中。

嘗試閱讀這個很好的教程。 http://use-the-index-luke.com/

如果在特定查詢中需要幫助,請提出另一個問題。包括以下信息:

  1. 查詢。
  2. EXPLAIN
  3. 的結果查詢中涉及的表的定義,包括索引。

專業提示:SELECT *在大量連接的大型查詢中對性能有害。特別是,

SELECT * 
    FROM gigantic_table 
    ORDER BY column 
    LIMIT 1 

是一個反模式,因爲它吸食龐大的數據量進行排序,然後丟棄所有,但的排序結果的一行。很多數據都會在您的服務器中出現一些小數據。這是浪費,即使它是正確的。您可以更有效地做這種事情與

SELECT * 
    FROM gigantic_table 
    WHERE column = 
      (SELECT MAX(column) FROM gigantic_table) 

最好的效率會來,如果column索引。

我提到這一點,因爲你explain的第一行,使它看起來像你嬉戲通過大量行的找東西。

相關問題