優化重點:
1 索引應該盡量小,使用字節數小的列建索引好(參照索引的創建),不要對有限的幾個值的字段建單一索引如性別字段。索引不能建得太多和太大。索引是把“雙刃劍”,查詢快,增刪改操作就會慢,而且有可能影響其他sql. 一般的20%的代碼占據了80%的資源,優化的重點是這些慢的地方。索引的使用要恰到好處,其使用原則如下:
●在經常進行連接,但是沒有指定為外鍵的列上建立索引,而不經常連接的字段則由優化器自動生成索引。
●在頻繁進行排序或分組(即進行group by或order by操作)的列上建立索引。
●在條件表達式中經常用到的不同值較多的列上建立檢索,在不同值少的列上不要建立索引。比如在雇員表的“性別”列上只有“男”與“女”兩個不同值,因此就無必要建立索引。如果建立索引不但不會提高查詢效率,反而會嚴重降低更新速度。
●如果待排序的列有多個,可以在這些列上建立復合索引(compound index)。
●group by或order by子句中列的次序與索引的次序盡量相同
● 避免非開始的子串,如zipcode[2,3] >“80” ;避免困難的正規表達式
2 如果是使用like進行查詢的話,簡單的使用索引是不行的,但是全文索引,耗空間。
3 注意使用DISTINCT,在沒有必要時不要用,它同union一樣會使查詢變慢。沒有必要時不要用ORDER BY
4 查詢時不要返回不需要的行、列。
5 用select top 100 / 10 Percent 來限制用戶返回的行數。(這個效果非常明顯,特別對大表)
6 不要在where字句中的列名加函數,如Convert,substring等,如果必須用函數的時候,創建計算列再創建索引來替代.還可以變通寫法:where SUBSTRING(firstname,1,1) = ’m’改為where firstname like ’m%’(索引掃描),一定要將函數和列名分開。
7 NOT IN會多次掃描表,使用exists、NOT exists ,IN , LEFT OUTER join 來替代,特別是左連接,而exists比IN更快,最慢的是NOT操作.現在2000的優化器能夠處理IS NULL,"NOT", "NOT exists", "NOT IN",而"<>", "!=", "!>", "!<"等還是不能優化,用不到索引。
8 OR用不到索引。可以用 union來代替。關鍵的問題是否用到索引.
1 SELECT * FROM CM_meterial WHERE (cMatCode=104 AND IMaxPrice>100.0) OR cMatCode=105
2 SELECT * FROM CM_meterial WHERE (cMatCode =104 AND IMaxPrice >100.0
UNION
SELECT * FROM orders WHERE cMatCode =105
注意這裡“IMaxPrice >100.0”因為IMaxPrice是Numeric類型,數字最好寫成100.0而不是100後者在數據庫實際執行時會認為成整型還會做convert操作
9 Between在某些時候比IN速度更快,Between能夠更快地根據索引找到范圍。
select * from chineseresume where title in (’男’,’女’)
select * from chineseresume where title between ’男’ and ’女’ 是一樣的。由於in會在比較多次,所以有時會慢些。
10 在IN後面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最後面,減少判斷的次數。
11 一般在GROUP BY個HAVING字句之前就能剔除多余的行,所以盡量不要用它們來做剔除行的工作。盡量在where中剔除最多條件。
12 一次更新多條記錄比分多次更新每次一條快,批處理好
13 避免相關子查詢。一個列的標簽同時在主查詢和where子句中的查詢中出現,那麼很可能當主查詢中的列值改變之後,子查詢必須重新查詢一次。查詢嵌套層次越多,效率越低,因此應當盡量避免子查詢。如果子查詢不可避免,那麼要在子查詢中過濾掉盡可能多的行。
14 查詢條件中不要包含運算
這些運算包括字符串連接(如:select * from Users where UserName + ‘pig’ = ‘張三pig’),通配符在前面的Like運算(如:select * from tb1 where col4 like ‘%aa’),使用其他用戶自定義函數、系統內置函數、標量函數等等(如:select * from UserLog where datepart(dd, LogTime) = 3)。
SQLServer在處理以上語句時,一樣沒辦法估算開銷。最終結果當然是clustered index scan或者table scan了。
15 查詢條件中不要包含同一張表內不同列之間的運算
所謂的“運算”包括加減乘除或通過一些function(如:select * from tb where col1 – col2 = 1997),也包括比較運算(如:select * from tb where col1 > col2)。這種情況下,SQLServer一樣沒辦法估算開銷。不論col1、col2上都有索引還是創建了col1、col2上的覆蓋索引還是創建了col1 include col2的索引。
但是這種查詢有解決辦法,可以在表上多創建一個計算字段,其值設置為你的“運算”結果,再在該字段上創建一個索引,就Ok了。
(結果集/總行數)被稱為選擇性,比值越大,選擇性就越高。
16 解釋計劃中能看到這兩個:
低效:Index Scan(索引掃描):就全掃描索引(包括根頁,中間頁和葉級頁)
高效:Index Seek(索引查找):
17 寫sql應該小表(記錄少)在前,大表(記錄多)在後;特別是主表,明細表,一定主表在前,明細表在後。驅動表是在使用多表嵌套連接時,會先全表掃描該驅動表,然後驅動表返回的結果集中一行一行去匹配被驅動表(可以利用索引),所以我們會選擇小表做為驅動表,而被驅動表使用索引進行連接。
18 合並算法(必須按相等列分別排序),hash(必須列相等連接,而不是類似left(1,3)函數相等)是有條件限制的,Nested Loops 嵌套循環適合小表連大表而且返回值不多時
19 低效
Index Scan(索引掃描):就全掃描索引(包括根頁,中間頁和葉級頁):
高效
Index Seek(索引查找):通過索引向前和向後搜索 :
20 select convert(char(10), st_stkrecord.ddate, 120) as ddate, order by ddate,會導致查詢用不到索引,應該在order by中寫成 st_stkrecord.ddate。這樣才能用到索引,否則只能建立函數索引了
21 嵌套的子查詢中根據查詢條件盡可能過濾過的記錄 如select *
from st_stkrecord s inner join (select * from where/*v中還用的查詢條件盡量在這裡將其過濾*/) v on(v.cguid = s.cguid)