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