1. 程式人生 > 實用技巧 >SQL語句優化-WHERE子句優化

SQL語句優化-WHERE子句優化

WHERE子句的優化

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
  • 索引使用的常量表達式只計算一次
  • 使用MyISAM和MEMORY儲存引擎的表,單表不帶WHERE子句,使用COUNT(*)會直接從表資訊中檢索
  • 早期會檢測無效常量表達式。MySQL會檢測到一些SELECT語句是總為false的,不返回任何行
  • 如果不使用GROUP BY或在HAVING子句中使用聚合函式(COUNT()、MIN()等),那麼HAVING將與WHERE合併
  • 對於有關聯關係的表,構造一個簡單的WHERE條件以快速地對錶進行WHERE求值,並儘可能快地跳過行
  • 在查詢過程中常量表的讀取在其它表之前。常量表是以下任何一種:
    • 一張空表或只有一行記錄的表
    • 使用了帶主鍵或者唯一索引的WHERE子句的表,其中所有索引部分都與常量表達式進行比較,並定義為NOT NULL(唯一索引要為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可以從索引中讀取記錄,甚至不需要通過資料檔案檢索。如果索引中使用的所有列都是數值,則只使用索引樹來解析查詢,如下:

    SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val; 
    // key_part1和key_part2都是數值索引
    
  • 在輸出每一行之前,跳過那些與 HAVING 子句不匹配的行