SQL Server的SQL語句性能優化總結

查看數據庫統計信息:

set statistics io on   set statistics time on

select  * from table1;

set statistics io off  set statistics time off

數據庫查詢常用優化:

1、不要使用select *, 使用select top 

在select中指定所需要的列,將帶來的好處: 
(1)減少內存耗費和網絡的帶寬 
(2)更安全 
(3)給查詢優化器機會從索引讀取所有需要的列

2、in 和 not in 要慎用,否則會導致全表掃描

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

3、對於連續的數值,能用 between 就不要用 in

select id from t where num between 1 and 3

4、使用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)

5、is null或is not null操作

應儘量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:

select id from t where num is null

最好不要給數據庫留NULL,儘可能的使用 NOT NULL填充數據庫. 
備註、描述、評論之類的可以設置爲 NULL,其他的,最好不要使用NULL。

不要以爲 NULL 不需要空間,比如:char(100) 型,在字段建立時,空間就固定了, 不管是否插入值(NULL也包含在內),都是佔用 100個字符的空間的,如果是varchar這樣的變長字段, null 不佔用空間。

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

select id from t where num = 0

6、用union替換or(適用於索引列)

通常情況下,用union替換where子句中的or將會起到較好的效果。對索引列使用or將造成全表掃描。注意:這個規則只針對多個索引列有效。如果有column沒有被索引,查詢效率可能會因爲你沒有選擇or而降低。下面的例子中loc_id和region上都有建索引。

(低效)select loc_id,loc_desc,begion from location where loc_id=10 or begion='MELBOURNE'; 

(高效)select loc_id,loc_desc,begion from location where loc_id=10
       union
       select loc_id,loc_desc_begion from location where begion='MELBOURNE'; 

7、優化group by---先條件過濾,在group by

提高group by語句的效率,可以通過將不需要的記錄在group by之前過濾掉。

(低效)select [job],avg([sal]) from [emp] group by [job] having job='PRESIDENT' or job='MANAGER'; 

(高效)select [job],avg([sal]) from [emp] where [job]='PRESIDENT' or job='MANAGER' group by [job];

8、<及>操作

大於或小於一般情況不用調整,因爲它有索引就會採用索引查找,但有的情況下可以對它進行優化。如一個表有100萬記錄,那麼執行>2與>=3的效果就有很大區別了。

(低效)select * from [emp] where [deptno]>2;
(高效)select * from [emp] where [deptno]>=3;

9、應儘量避免在 where 子句中使用 or 來連接條件

如果一個字段有索引,一個字段沒有索引,將導致引擎放棄使用索引而進行全表掃描,如:

select id from t where num=10 or Name = 'admin'

可以這樣查詢:

select id from t where num = 10
union all
select id from t where Name = 'admin'

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 name like 'abc%' 

12、儘量避免使用前置百分號。

select id from t where name like '%abc%' 

13、Update 語句,如果只更改1、2個字段,不要Update全部字段,否則頻繁調用會引起明顯的性能消耗,同時帶來大量日誌。

14、對於多張大數據量(這裏幾百條就算大了)的表JOIN,要先分頁再JOIN,否則邏輯讀會很高,性能很差。

15、select count(*) from table;這樣不帶任何條件的count會引起全表掃描,並且沒有任何業務意義,是一定要杜絕的。

16、索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因爲 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。

17、並不是所有索引對查詢都有效,SQL根據表中數據來進行查詢優化,當索引列有大量數據重複時,SQL查詢可能不會去利用索引。

18、索引並不是越多越好,索引提交了select效率,但是降低了insert和update的效率。一個表的索引數最好不要超過6個

19、儘量使用數字型字段,若只含數值信息的字段儘量不要設計爲字符型,這會降低查詢和連接的性能,並會增加存儲開銷。因爲引擎在處理查詢和連接時會逐個比較字符串中每個字符,而對於數字型而言只需要比較一次就夠了。

20、儘可能使用varchar/nvarchar代替char/nchar,因爲首先變長字段存儲空間小,可以節省存儲空間;其次對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。

21、任何地方都不要使用select ,用具體的字段列表代替,不要返回用不到的字段。

22、儘量避免使用遊標,因爲遊標的效率較差,如果遊標操作的數據超過1萬行,那麼就考慮改寫。

23、儘量避免大事務操作,提高系統併發能力。

24、應儘量避免在 where 子句中使用 != 或 <> 操作符,否則將引擎放棄使用索引而進行全表掃描。

25、對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引

26、儘量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。

27、避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個數據集時。但是,對於一次性事件, 最好使用導出表。

28、在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,爲了緩和系統表的資源,應先create table,然後insert。

29、如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

30、使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

31、與臨時表一樣,遊標並不是不可使用。對小型數據集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時 間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

32、在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。

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