1. 程式人生 > >4.SQL優化之Where語句

4.SQL優化之Where語句

1 優化Where語句

以下優化適用於使用SELECT語句,但相同的優化適用於DELETE和UPDATE語句中的WHERE子句。

為了優化查詢,有時我們可能考慮犧牲程式可讀性,但是MySQL在生成執行計劃時會對SQL進行改寫,所以我們不需要過度改寫,儘量保證可讀性,只有在效能無法滿足的基礎上在按照自我理解進行重寫SQL,以下是幾種MySQL自動進行的SQL改寫的例子:

  • 刪除不必要的括號:

     	((a AND b) AND c OR (((a AND b) AND (c AND d)))) -> (a AND b AND c) OR (a AND b AND c AND d)
    
  • 常數摺疊

      (a<b AND b=c) AND a=5 -> b>5 AND b=c AND a=5
    
  • 恆定條件去除

      (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)-> B=5 OR B=6
    
  • 索引所使用的常數表示式僅計算一次。

  • 沒有Where條件的MyISAM和MEMORY儲存引擎中統計count(*)時,計算是通過表定義計算獲得,所以效率很高。使用一個not null的表示式也可以達到這個效果。

  • 某些SQL是不可能返回rows的,MySQL會提前檢測出來然後直接返回。

  • 如果不使用GROUP BY或聚合函式(COUNT(),MIN()等),HAVING將與WHERE合併。

  • 對於每一個表連線,構造一個更簡單的Where條件已獲得更好的執行計劃,儘可能的跳過更多不需要掃描的行。

  • 在執行所有查詢之前,首先讀取常量表(常量表定義如下):

    • 空表或者只有1行資料的表

    • 與PRIMARY KEY或UNIQUE索引上的WHERE子句一起使用的表,其中所有索引部分與常數表示式進行比較,並定義為NOT NULL。

        SELECT * FROM t WHERE primary_key=1;
        SELECT * FROM t1,t2
          WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
      
  • 通過嘗試所有可能性,可以找到加入表格的最佳連線組合。 如果ORDER BY和GROUP BY子句中的所有列都來自同一個表,則在加入時首先首選該表。

  • 如果存在ORDER BY子句和不同的GROUP BY子句,或者ORDER BY或GROUP BY包含連線佇列中第一個表以外的表中的列,則會建立臨時表。

  • 如果使用SQL_SMALL_RESULT修飾符,MySQL將使用記憶體中的臨時表。

  • 首先查詢每個表索引,並使用最佳索引,除非優化程式認為使用表掃描更有效。 在以前,根據最佳索引是否跨越表的30%來使用掃描,但固定百分比不再決定使用索引或掃描之間的選擇。 優化器現在更復雜,並且基於其他因素(例如表大小,行數和I/O塊大小)進行估算。

  • 在某些情況下,MySQL甚至無需查閱資料檔案即可從索引中讀取行。 如果索引中使用的所有列都是數字,則僅使用索引樹來解析查詢。

  • 在輸出每一行之前,將跳過與HAVING子句不匹配的行。

一些查詢效率較高的SQL樣例

SELECT COUNT(*) FROM tbl_name;

SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;

SELECT MAX(key_part2) FROM tbl_name
  WHERE key_part1=constant;

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... LIMIT 10;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;

在索引列是數字的情況下MySQL僅使用索引樹解析以下查詢

SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;

SELECT COUNT(*) FROM tbl_name
  WHERE key_part1=val1 AND key_part2=val2;

SELECT key_part2 FROM tbl_name GROUP BY key_part1;

以下查詢使用索引來按排序順序檢索行,而不需要排序操作:

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... ;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... ;