天天看點

Sql 索引優化

SQL語句優化

優化查詢(大部分是索引相關):

  1. 查詢from從右向左,表記錄少的放右邊,盡量使用内置函數;
  2. 避免全表掃描,盡量使用多表連接配接(join)查詢(避免子查詢);
  3. 使用索引遵循最佳左字首特性;
  4. 在 where 及 order by 涉及的列上建立索引。

    索引失效而進行全表掃描的情況:

    1. 在 where 子句中,使用 != 或 <> 或 is null 或 or 連接配接條件(or分割開的條件必須每列都有索引,才會走索引)也可避免:

      select id from t where num=10

      union all

      select id from t where num=20

    2. like ‘%abc%’ 、in 和 not in (可以NOT EXISTS代替)
    3. 在 where 子句中使用參數。因為SQL隻有在運作時才解析局部變量,但優化程式不能将通路計劃的選擇推遲到運作時;須在編譯時進行選擇。然而,如果在編譯時建立通路計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下将全表掃描:

      select id from t where [email protected]

      可以改為強制查詢使用索引:

      select id from t with(index(索引名)) where [email protected]

    4. 應盡量避免在 where 子句中對字段進行表達式和函數操作,資料類型隐式轉換
    5. 不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算
    6. 索引字段作為條件時,複合索引必須使用到該索引中的第一個字段作為條件才能保證系統使用該索引,并且應盡可能的讓字段順序與索引順序相一緻。
    7. 并不是所有索引對查詢都有效,SQL根據資料查詢優化,當索引列有大量資料重複時,SQL查詢可能不會去索引,如一表中有字段sex幾乎各一半,即使在sex上建了索引也對查詢效率起不了作用。
    8. 索引并不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,是以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個。
    9. 應盡可能的避免更新 clustered 索引資料列,因為 clustered 索引資料列的順序就是表記錄的實體存儲順序,一旦該列值改變将導緻整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應将該索引建為 clustered 索引。
  5. 不要寫一些沒有意義的查詢,會消耗系統資源,如需要生成一個空表結構:應改成這樣:create table #t(…)
  6. 很多時候用 exists 代替 in 是一個好的選擇:

    select num from a where num in(select num from b)

    用下面的語句替換:

    select num from a where exists(select 1 from b where num=a.num)

  7. 任何地方都不要使用 select * from t ,用具體的字段清單代替“*”。

    表設計、臨時表請況:

  8. 盡量使用數字型字段,若隻含數值資訊的字段盡量不要設計為字元型,這會降低查詢和連接配接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接配接時會逐個比較字元串中每一個字元,而對于數字型而言隻需要比較一次就夠了。
  9. 盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對于查詢來說,在一個相對較小的字段内搜尋效率顯然要高些
  10. 盡量使用表變量來代替臨時表。如果表變量包含大量資料,請注意索引非常有限(隻有主鍵索引)。
  11. 避免頻繁建立和删除臨時表,以減少系統表資源的消耗。
  12. 臨時表并不是不可使用,适當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對于一次性事件,最好使用導出表。
  13. 建立臨時表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果資料量不大,為了緩和系統表的資源,應先create table,然後insert。
  14. 如果使用到了臨時表,在存儲過程的最後務必将所有的臨時表顯式删除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
  15. .盡量避免使用遊标,因為遊标的效率較差,如果遊标操作的資料超過1萬行,那麼就應該考慮改寫。
  16. 使用基于遊标的方法或臨時表方法之前,應先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。
  17. 與臨時表一樣,遊标并不是不可使用。對小型資料集使用 FAST_FORWARD 遊标通常要優于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的例程通常要比使用遊标執行的速度快。如果開發時間允許,基于遊标的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
  18. 在所有的存儲過程和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向用戶端發送 DONE_IN_PROC 消息。
  19. 盡量避免向用戶端傳回大資料量,若資料量過大,應該考慮相應需求是否合理。
  20. 盡量避免大事務操作,提高系統并發能力。
  21. 主從複制,讀寫分離與分庫分表

建立索引的情況 索引是對資料庫表中一列或多列的值進行排序的一種結構

主鍵限制預設建立唯一索引

頻繁作為查詢條件的字段應該建立索引

多表查詢中與其它表進行關聯的字段,外鍵關系建立索引

單列索引/複合索引的選擇? 高并發下傾向于建立複合索引

查詢中經常用來排序的字段

查詢中經常用來統計或者分組字段

不建立索引的情況

頻繁更新的字段: 每次更新都會影響索引樹

where條件查詢中用不到的字段

表記錄太少

經常增删改的表: 更新了表,索引也得更新才行

注意: 如果一張表中,重複的記錄非常多,為它建立索引就沒有太大意義

繼續閱讀