30種簡單的sql優化方法

同樣的數據表,同樣的查詢條件,爲什麼有的執行時間2、3秒甚至更多,有的卻只需要2毫秒。就是因爲sql語句的差異。

以下是我在網上搜集的一些sql語句優化方式,暫做筆記。

  1. 合理的建立索引。首選在where查詢條件和order by字段上建立索引。
  2. 儘量避免在 where 子句中使用!=或<>操作符,否則將使用全表掃描,索引作廢。
  3. 儘量避免在where中進行null值的判斷,否則將使用全表掃描,索引作廢。例如:select  * from table_name where name = null  ;   解決辦法就是將表中的name字段默認值設置爲“”(空字符串),剔除null值的存在,查詢時使用select  * from table_name where name = ‘’
  4. 不在查詢條件中使用or關鍵詞,否則將使用全表掃描,索引作廢。例如:select * from table_name where age = 18 or age = 19 ;  解決辦法是使用 union all 關鍵詞,如下:select * from table_name where age = 18  union all  select * from table_name where age =19
  5. 儘量不使用模糊查詢。例如:select *  from table_name where name like '張%'
  6. 儘量不使用in not  in進行判斷,連續的數值可以使用between。例如:select * from table_name where age in(18,19,20,21); 優化成:select * from table_name where age between 18 and 21 ;
  7. 儘量不在where 條件語句中使用參數。因爲SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作爲索引選擇的輸入項。如下語句將進行全表掃描: select id from t where age = ${age}。 可以改爲強制查詢使用索引:  select id from t with ( index(索引)) where age=${age} 暫時還沒理解什麼意思。
  8. 儘量避免在 where 子句中對字段進行表達式操作,否則將使用全表掃描,索引作廢。如下 : select * from user where salary/2 = 2000 ;   可以優化成select * from user where salary = 2000*2
  9. 儘量避免在where子句中對字段進行函數操作,否則將使用全表掃描,索引作廢。例如:select * from user where  substring(name,0,2)='abc' 。 這個語句可以查詢出所有姓名以abc開頭的信息。優化爲 select * from user where  name like 'abc%' ; (好像函數操作的問題比模糊查詢的問題更嚴重,<> ! 操作符也是如此。)
  10. 不要在 “=”  進行判斷以及函數操作和計算。
  11. 在使用索引字段作爲條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個字段作爲條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓字段順序與索引順序相一致。
  12. 學會用exists 替代in select * from a where age in (select age from b) 用下面的語句替換: select age from a where exists(select age  from b where age =a.age)。
  13. 不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,如一表中有字段name,age 、id,nation幾乎各一半,這時即使在name上建了索引也對查詢效率起不了作用。
  14. 索引並不是越多越好,索引在提高 select語句效率的同時也降低了 insert 及 update 的效率,因爲 insert 或 update 時有可能會重建索引,所以建索引需要視具體情況而定。建議一張表的索引不超過6個。
  15. 應儘可能的避免更新 clustered 索引數據列,因爲 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那麼需要考慮是否應將該索引建爲 clustered 索引。
  16. 儘量使用數字型字段。若一個字段只含數字形式的信息,則儘可能的設計成數值類型,否則會降低查詢和連接的性能,並會增加存儲開銷。這是因爲引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了。
  17. 儘可能的使用 varchar/nvarchar 而不是 char/nchar ,因爲變長字段存儲空間小,可以節省存儲空間。而且對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
  18. 儘量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。
  19. 避免頻繁創建和刪除臨時表,表結構越穩定,越能減少對系統資源的消耗,sql 效率越高。
  20. 但對於一次性事件,最好使用導出表。儘量不使用臨時表。
  21. 在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,爲了緩和系統表的資源,應先create table,然後insert。
  22. 如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
  23. 儘量避免使用遊標,因爲遊標的效率較差,如果遊標操作的數據超過1萬行,那麼就應該考慮改寫。
  24. 使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
  25. 與臨時表一樣,遊標並不是不可使用。對小型數據集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
  26. 在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。
  27. 儘量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
  28. 儘量避免大事務操作,提高系統併發能力。
  29. 查詢時儘量返回具體的字段,避免返回無用信息。不要出現select  * from user,要多使用 select name,age from user。本文只是爲了舉例方便纔用到了* 。

總而言之,就是儘可能的避免全表掃描。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章