1.對查詢進行最佳化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
2.應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0
3.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
4.應盡量避免在 where 子句中使用 or 來串連條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
5.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
6.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索索引。
7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但最佳化程式不能將訪問計劃的選擇延遲到運行時;它必須在編譯時間進行選擇。然而,如果在編譯時間建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num
8.應盡量避免在 where 子句中對欄位進行運算式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2
9.應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’產生的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的“=”左邊進行函數、算術運算或其他運算式運算,否則系統將可能無法正確使用索引。
11.在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓欄位順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如需要產生一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)
13.很多時候用 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)
14.並不是所有索引對查詢都有效,SQL是根據表中資料來進行查詢最佳化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。
15.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要謹慎考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
16.應儘可能的避免更新 clustered 索引資料列,因為 clustered 索引資料列的順序就是表記錄的實體儲存體順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。
17.盡量使用數字型欄位,若只含數值資訊的欄位盡量不要設計為字元型,這會降低查詢和串連的效能,並會增加儲存開銷。這是因為引擎在處理查詢和串連時會逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。
18.儘可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位儲存空間小,可以節省儲存空間,其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。
19.任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。
20.盡量使用表變數來代替暫存資料表。如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。
21.避免頻繁建立和刪除暫存資料表,以減少系統資料表資源的消耗。
22.暫存資料表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,最好使用匯出表。
23.在建立暫存資料表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果資料量不大,為了緩和系統資料表的資源,應先create table,然後insert。
24.如果使用到了暫存資料表,在預存程序的最後務必將所有的暫存資料表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統資料表的較長時間鎖定。
25.盡量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。
26.使用基於遊標的方法或暫存資料表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
27.與暫存資料表一樣,遊標並不是不可使用。對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的常式通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
28.在所有的預存程序和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。無需在執行預存程序和觸發器的每個語句後向用戶端發送 DONE_IN_PROC 訊息。
29.盡量避免大事務操作,提高系統並發能力。
30.盡量避免向用戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。
具體的SQL語句在很多情況下需要結合實際的應用情況來寫,這裡不作敘述。
sql效能2
1 邏輯資料庫和表的設計
資料庫的邏輯設計、包括表與表之間的關係是最佳化關係型資料庫效能的核心。一個好的邏輯資料庫設計可以為最佳化資料庫和應用程式打下良好的基礎。
標準化的資料庫邏輯設計包括用多的、有相互關係的窄表來代替很多列的長資料表。下面是一些使用標準化表的一些好處。
A:由於表窄,因此可以使排序和建立索引更為迅速
B:由於多表,所以多鏃的索引成為可能
C:更窄更緊湊的索引
D:每個表中可以有少一些的索引,因此可以提高insert update delete等的速度,因為這些操作在索引多的情況下會對系統效能產生很大的影響
E:更少的空值和更少的多餘值,增加了資料庫的緊湊性由於標準化,所以會增加了在擷取資料時參考資料表的數目和其間的串連關係的複雜性。太多的表和複雜的串連關係會降低伺服器的效能,因此在這兩者之間需要綜合考慮。
定義具有相關關係的主鍵和外來鍵時應該注意的事項主要是:用於串連多表的主鍵和參考的鍵要有相同的資料類型。
2 索引的設計
A:盡量避免表掃描
檢查你的查詢語句的where子句,因為這是最佳化器重要關注的地方。包含在where裡面的每一列(column)都是可能的侯選索引,為能達到最優的效能,考慮在下面給出的例子:對於在where子句中給出了column1這個列。
下面的兩個條件可以提高索引的最佳化查詢效能!
第一:在表中的column1列上有一個單索引
第二:在表中有多索引,但是column1是第一個索引的列
避免定義多索引而column1是第二個或後面的索引,這樣的索引不能最佳化伺服器效能
例如:下面的例子用了pubs資料庫。
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White’
按下面幾個列上建立的索引將會是對最佳化器有用的索引
?au_lname
?au_lname, au_fname
而在下面幾個列上建立的索引將不會對最佳化器起到好的作用
?au_address
?au_fname, au_lname
考慮使用窄的索引在一個或兩個列上,窄索引比多索引和複合索引更能有效。用窄的索引,在每一頁上將會有更多的行和更少的索引層級(相對與多索引和複合索引而言),這將推進系統效能。
對於多列索引,SQL Server維持一個在所有列的索引上的密度統計(用於聯合)和在第一個索引上的histogram(柱狀圖)統計。根據統計結果,如果在複合索引上的第一個索引很少被選擇使用,那麼最佳化器對很多查詢請求將不會使用索引。
有用的索引會提高select語句的效能,包括insert,uodate,delete。
但是,由於改變一個表的內容,將會影響索引。每一個insert,update,delete語句將會使效能下降一些。實驗表明,不要在一個單表上用大量的索引,不要在共用的列上(指在多表中用了參考約束)使用重疊的索引。
在某一列上檢查唯一的資料的個數,比較它與表中資料的行數做一個比較。這就是資料的選擇性,這比較結果將會協助你決定是否將某一列作為侯選的索引列,如果需要,建哪一種索引。你可以用下面的查詢語句返回某一列的不同值的數目。
select count(distinct cloumn_name) from table_name
假設column_name是一個10000行的表,則看column_name傳回值來決定是否應該使用,及應該使用什麼索引。
Unique values Index
5000 Nonclustered index
20 Clustered index
3 No index
鏃索引和非鏃索引的選擇
<1:>鏃索引是行的物理順序和索引的順序是一致的。頁級,低層等索引的各個層級上都包含實際的資料頁。一個表只能是有一個鏃索引。由於update,delete語句要求相對多一些的讀操作,因此鏃索引常常能加速這樣的操作。在至少有一個索引的表中,你應該有一個鏃索引。
在下面的幾個情況下,你可以考慮用鏃索引:
例如: 某列包括的不同值的個數是有限的(但是不是極少的)
顧客表的州名列有50個左右的不同州名的縮寫值,可以使用鏃索引。
例如: 對返回一定範圍內值的列可以使用鏃索引,比如用between,>,>=,<,<=等等來對列進行操作的列上。
select * from sales where ord_date between ’5/1/93’ and ’6/1/93’
例如: 對查詢時返回大量結果的列可以使用鏃索引。
SELECT * FROM phonebook WHERE last_name = ’Smith’
當有大量的行正在被插入表中時,要避免在本表一個自然增長(例如,identity列)的列上建立鏃索引。如果你建立了鏃的索引,那麼insert的效能就會大大降低。因為每一個插入的行必須到表的最後,表的最後一個資料頁。
當一個資料正在被插入(這時這個資料頁是被鎖定的),所有的其他插入行必須等待直到當前的插入已經結束。
一個索引的葉級頁中包括實際的資料頁,並且在硬碟上的資料頁的次序是跟鏃索引的邏輯次序一樣的。
<2:>一個非鏃的索引就是行的物理次序與索引的次序是不同的。一個非鏃索引的葉級包含了指向行資料頁的指標。
在一個表中可以有多個非鏃索引,你可以在以下幾個情況下考慮使用非鏃索引。
在有很多不同值的列上可以考慮使用非鏃索引
例如:一個part_id列在一個part表中
select * from employee where emp_id = ’pcm9809f’
查詢語句中用order by 子句的列上可以考慮使用鏃索引
3 查詢語句的設計
SQL Server最佳化器通過分析查詢語句,自動對查詢進行最佳化並決定最有效執行方案。最佳化器分析查詢語句來決定那個子句可以被最佳化,並針對可以被最佳化查詢的子句來選擇有用的索引。最後最佳化器比較所有可能的執行方案並選擇最有效一個方案出來。
在執行一個查詢時,用一個where子句來限制必須處理的行數,除非完全需要,否則應該避免在一個表中無限制地讀並處理所有的行。
例如下面的例子,
select qty from sales where stor_id=7131
是很有效比下面這個無限制的查詢
select qty from sales
避免給客戶的最後資料選擇返回大量的結果集。允許SQL Server運行滿足它目的的函數限制結果集的大小是更有效。
這能減少網路I/O並能提高多使用者的相關並發時的應用程式效能。因為最佳化器關注的焦點就是where子句的查詢,以利用有用的索引。在表中的每一個索引都可能成為包括在where子句中的侯選索引。為了最好的效能可以遵照下面的用於一個給定列column1的索引。
第一:在表中的column1列上有一個單索引
第二:在表中有多索引,但是column1是第一個索引的列不要在where子句中使用沒有column1列索引的查詢語句,並避免在where子句用一個多索引的非第一個索引的索引。
這時多索引是沒有用的。
For example, given a multicolumn index on the au_lname, au_fname columns of the authors table in
the pubs database,
下面這個query語句利用了au_lname上的索引
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White’
AND au_fname = ’Johnson’
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White’
下面這個查詢沒有利用索引,因為他使用了多索引的非第一個索引的索引
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_fname = ’Johnson’