如何寫出效能好的sql

老皆知發表於2013-11-08

開發人員是很少注意SQL對資料庫效能影響的重要性的,大多程式設計師都會認為SQL是比較簡單的,需要的時候查查手冊就可以了,很少有深究的。

這樣的觀念對大型系統的開發是致命的,需要糾正這樣的觀念。

造成這樣的原因,可能有如下幾種:

1,對資料庫效能的研究,成果不是顯而易見,對程式設計師的成就感激勵不足,因為開發環境中的資料很少,資料庫效能好壞體現不出來,好的sql和差的sql體現不出差別,所以,更多的人選擇的是寫出來就可以了,沒有想到過效能。沒有吃過這方面的虧,沒有深刻的教訓,人總是要有了教訓才會重視,而以教訓作為學習方法其實是很高成本的。

2,程式設計師更重視能寫多少功能,會多少語言,對於一些不是顯而易見和不好衡量的能力是不夠重視的。

今天客戶的一套系統因為一段sql沒有考慮效能問題,導致資料在幾萬條資料的情況下,竟然也出現了巨大的效能開銷,導致系統癱瘓無法使用的狀況,所以,覺得有必要將一些心得寫出來與大家共享。

索引是非常重要的,但是很多人是不重視的。

我總是不厭其煩的向很多開發人員介紹索引的重要性,但是,很多時候都可以從他們臉上看出來那種不以為然,但我還是在不厭其煩的向他們講解,因為索引能否正確使用對系統的效能太重要了。

我覺得幾個重要而簡單的概念應該是必須掌握的:

a.聚集索引和非聚集索引,各應該用在什麼場合

b.什麼樣的語句會使用索引,什麼樣的語句將不使用索引

c.應該在什麼樣的欄位上面建立索引

d.複合索引的使用特點

一些具體的規則,如果不能理解,死記住也會獲益

1,經常用來做聯接的欄位上面加索引

2,經常用來做條件的欄位上面加索引

3,堅決避免在條件中使用否定意義的計算符,如:

      select * from table1 where column1 not in (select column2 from table2)

      select * from table1 where column1 not exists (select column2 from table2)

     select * from table1 where id <> 100

4,聚集索引能對範圍查詢的效能產生巨大的提升,一定要善加利用,但是如果使用不當,也會帶來巨大的效能損失

     如你可以將一個訂單表的訂單日期加上聚集索引,訂單日期是遞增的,這樣你按照日期範圍查詢時,你將獲得最高的效能

     select * from 客戶訂單 where 訂單日期 between '2005-1-1' and '2005-1-31'  --是範圍的查詢

    但是你把客戶編號作為聚集索引,將不會帶來重大的效能提升,反而會有負效果,因為訂單的順序客戶編號是非順序的,這樣由於聚集索引需要重新排列物理磁碟,這樣將會給資料寫入帶來巨大的開銷

5,不要在生成順序不規則的欄位上面加聚集索引,應該選擇能夠按照遞增或遞減順序生成資料的欄位作為聚集索引的欄位

6,堅決避免對條件欄位何作為連線的欄位進行運算,甚至使用函式,如:

      select * from UserInfo where firstname + lastname = 'Bill Gates'

      select * from UserInfo where dbo.fGetBasicSalary(UserInfo.UserId) = 2000

      select * from table1 inner join table2  on table1.A + table1.B = table2.C

7,建立索引是有必要的,但不是越多越好      

8,可能的話,主鍵多用整型值,用一個整型欄位做連線,比一個字串在大資料量的情況下效能會提高很多

9,不要把大數量的內容放到 in ()裡面,如避免如下寫法:

      select * from table1 where column1 in (select column2 from table2) --如果此時table2的資料量比較大的情況下,效能將會非常差

      其實類似的語句經常可以改寫為連線的方式來實現

10,經常用來Order By的欄位加上索引,也會有效能的提升

11,子查詢不要出現太多,大多數能夠使用外連線來替代

select *,
(select z1 from T1 where z2=T2.Id) z1,
(select z2 from T1 where z2=T2.Id) z2,
(select z3 from T1 where z2=T2.Id) z3,
from T2

這段語句肯定不是優化的,會有效能問題的,可以有如下的方式來改寫

select *, T1.Z1, T1.Z2, T1.Z3

from T2 left outer join T1 on T1.Z2 = T2.ID

12,對於like的使用

       推薦:select * from 使用者 where 姓名 like '李%'

       不推薦:select * from 使用者 where 姓名 like '%白%'
 

建議:

      寫點東西算作拋磚引玉吧,希望能給一些資料庫初學者一些指引和建議吧!

      還有就是,如果我們的系統出現了效能的問題,多從軟體的角度來考慮優化,而不是動不動就要求客戶升級伺服器,硬體的改善對效能的提升能力是很有限的,提高一倍,兩倍都是很厲害的了,而軟體的優化有時候能起到數十倍,上百倍,甚至更高的效能提升。

      呼籲大家提高對資料效能的重視。

 

檢視執行時間

declare @d datetime 

  set @d=getdate() 

  並在select語句後加: 

  select [語句執行花費時間(毫秒)]=datediff(ms,@d,getdate()) 

相關文章