sql 語句優化

1.避免where子句使用 or 來鏈接條件

select * from orders where (customer_num=104 and order_num>100) or order_num = 1008sql

雖然在customer_num 和order_num 上建有索引,可是在上面的語句中優化器仍是使用順序存取路徑掃描整個表。由於這個語句要檢索的是分離行的集合,改爲併發

select * from orders where (customer_num=104 and order_num>100)
    union
select * from order where  order_num = 1008

2.避免相關子查詢函數

一個 例的標籤同時在主查詢和where子句中的查詢中出現,那麼極可能當主查詢中的列值改變以後,子查詢必須從新查詢一次,查詢嵌套層次越多,效率越低,所以應當儘可能避免子查詢。若是子查詢不可避免那麼要在子查詢中過濾掉儘量個人行post

3.避免困難的正規表達式 like性能

matches 和 like 關鍵字支持通配符匹配,技術上叫正規表達式,但這種匹配特別耗費時間,例:優化

select * from customer where zipcode like '98_ _ _'
select id from customer where name like '%abc%';

即便在zipcode字段上創建了索引,在這種狀況下也是採用掃描的方式。若是把語句改成設計

select * from customer where zipcode > '98000'

 在執行查詢時就會利用索引來查詢,顯然會大大提升速度。code

4.使用臨時表加速查詢排序

把表的一個子集進行排序並建立臨時表,有時能加速查詢。有助於避免多重排序操做,並且在其餘方面還有簡化優化器的工做。例如:索引

select cus.name , rcvbles.balance , ,,,
from cust , rcvbles
where cus.customer_id = rcvlbes.customer_id
and rcvblls.balance>0
and cus.postcode > '98000'
order by cust.name

若是這個查詢要被執行屢次而不止一次,可能把全部未付款的客戶找出來放在一個臨時文件中,並按客戶的名字進行排序:

select cus.name , rcvbles.balance , ,,,
from cust , rcvbles
where cus.customer_id = rcvlbes.customer_id
and rcvblls.balance>0
order by cust.nameinto temp cust_with_balance

而後如下面的方式在臨時表中查詢:

select * from cust_with_balance
where poscode > '98000'

臨時表中的行要比主表中和行少,並且物理順序就是所要求的順序,減小了磁盤i/o,因此查詢工做量能夠獲得大幅減小。

 臨時表建立後不會反映主表的修改。在主表中數據頻繁修改的狀況下,注意不要丟失數據  

5.考慮在where 及 order by 涉及的列上創建索引

6. 避免在 where 子句中對字段進行null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如

select id from t where num is null

能夠在num 上設置默認值0,確保表中num列沒有null值,而後這樣查詢:

select id from t where num = 0

7.避免在wher 子句中使用 != 或 <> 操做符,不然將致使引擎放棄索引進行全表掃描

8. in 和 not in 也要慎用,不然會致使全表掃描,如

select id from t where num in(1,2,3)

對於連續的數值,能用between就不要用in 了:

select id from t where num between 1 and 3

9.若是在where 子句中使用參數,也會致使全表掃描

select id from t where num=@num <mailto:num=@num>

可改成強制查詢使用索引:

select id from t with(index(索引名)) where num=@num <mailto:num=@num>

由於sql只有在運行時都會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時它必須在編譯時進行選擇。然而,若是在編譯時創建訪問計劃,變量的值學是未知的,於是沒法做爲索引選擇的輸入項。

10. 避免在where 子句中對字段進行表達式操做,這將致使引擎放棄索引

select id from t where num/2 = 100

select id from t where num = 100*2

11. 避免在where 子句中地字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描

如:

select id from t where substring(name,1,3) = 'abc'

select id from t where datediff(day,createdate,'2005-11-30')

select id from t where name like 'abc%'

select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'

12.不要在where 子句的 ‘=’ 左邊進行函數,算術運算或其餘形式運算,不然系統將可能沒法正確使用索引

13.使用數字型字段

若只含數據值的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和鏈接時會逐個比較字符中每個字符,而對於數字型而言只須要比較一次就夠了。

14.儘量的使用 varchar/nvarchar 代替 char/nchar

由於首先變長字段存儲空間小,可節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。

15.任何地方都不要使用select * from t, 用具體的字段列表代替 ‘*’ ,不要返回用不到的任何字段

16.用表變量代替臨時表

若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)

17.避免頻繁建立和刪除臨時表,以減小系統資源的消耗

18. 臨時表並非不可以使用,適當地使用它們可使某些例程理有效,例如,當須要重複引用大型表或經常使用表中的某個數據集時,
可是,對於一次性事件,最好使用導出表

19.在臨時表時,若是一次性插入數據量很大,那麼可使用 select into 代替 create table ,避免形成大量 log,以提升速度;
若是數據量不大,爲了緩和系統表的資源,應先 create table ,而後 insert

20.若是使用到了臨時表,在存儲過程最後務必將全部的臨時表顯示刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定

21.儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫

22.在全部的存儲過程和觸發器的開始處設置 set nocount no ,在結束時設置 set nocount off,無需在執行存儲過程和觸發器的每一個語句後向客戶發送 done_in_proc 消息

23.儘可能避免大事務操做,提升系統併發能力。

24.量避免向客戶端返回在數據量,若數據量過大,應該考慮相應需求是否合理

相關文章
相關標籤/搜索