數據庫常用查詢語句寫法(優化)
常用查詢寫法
Like
like本身效率就比較低,應該盡量避免查詢條件使用like;
原因:
- 對於like ‘%...%’(全模糊)這樣的條件,是無法使用索引的,全表掃描自然效率很低;
- 由於匹配算法的關系,模糊查詢的字段長度越大,模糊查詢效率越低。
解決辦法:
- 盡量避免模糊查詢,如果因為業務需要一定要使用模糊查詢,則至少保證不要使用全模糊查詢,對於右模糊查詢,即like ‘…%’,是會使用索引的;
- 左模糊like‘%...’無法直接使用索引,但可以利用reverse + function index 的形式,變化成 like ‘…%’;
- 全模糊是無法優化的,一定要的話考慮用搜索引擎。出於降低數據庫服務器的負載考慮,盡可能地減少數據庫模糊查詢。
NULL
原因:
- 查詢字段IS NULL時單索引失效,引起全表掃描。
解決方法:
- SQL語法中使用NULL會有很多麻煩,最好索引列都是NOT NULL的;
- 對於is null,可以建立組合索引,nvl(字段,0),對表和索引analyse後,is null查詢時可以重新啟用索引查找,但是效率還不是值得肯定;
- is not null 時永遠不會使用索引。一般數據量大的表不要用is null查詢。
<>、!=
原因:
- SQL中,不等於操作符會限制索引,引起全表掃描,即使比較的字段上有索引。
解決方法:
- 通過把不等於操作符改成OR,可以使用索引,避免全表掃描。例如,把column<>’aaa’,改成column<’aaa’ OR column>’aaa’,就可以使用索引了。
OR
原因:
- where子句中比較的兩個條件,一個有索引,一個沒索引,使用or則會引起全表掃描。例如:where A==1 or B==2,A上有索引,B上沒索引,則比較B=:2時會重新開始全表掃描,可以獲取兩個條件的數據,然後采用union all。
組合索引
- 排序時應按照組合索引中各列的順序進行排序,即使索引中只有一個列是要排序的,否則排序性能會比較差。【索引中包含排序字段】
Update
- 如果只更改1、2個字段,不要Update全部字段,否則頻繁調用會引起明顯的性能消耗,同時帶來大量日誌。
多張大數據量
- 先分頁再JOIN,否則邏輯讀會很高,性能很差。
COUNT函數
- 不帶任何條件的count會引起全表掃描,並且沒有任何業務意義,是一定要杜絕的。
IN 和 NOT IN
- 對於連續的數值,用 between:
select id from t where id in(1,2,3) => select id from t where id between 1 and 3 |
- 用EXISTS代替IN;NOT EXISTS代替NOT IN。
A/B
原因:
- 不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
- 引擎放棄使用索引而進行全表掃描
解決方法:
select id from t where id/2 = 10 => select id from t where id = 2 * 10 |
SUBSTRING/ DATEDIFF
原因:
- 不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
- 引擎放棄使用索引而進行全表掃描。
解決方法:
select id from t where substring(id,1,2) = ‘abcd’ => select id from t where id like ‘abcd%’ |
select id from t where datediff(day,createdate,’2017-09-08′) = 0 => select id from t where createdate >= ‘2016-11-30‘ and createdate < ‘2016-12-1‘ |
沒有意義的查詢
原因:
- 不會返回任何結果集,但是會消耗系統資源。例如:
- select col1,col2 into #t from t where 1=0
- select id from t with(index(索引名)) where ID= @id
強制使用索引
- select id from t with(index(索引名)) where ID= @id
建議
1) 盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
2) 任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
3) 盡量使用表變量來代替臨時表。如果表變量包含大量數據,請註意索引非常有限(只有主鍵索引)
4) 避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件, 最好使用導出表。
5) 在新建臨時表時,如果一次性插入數據量很大,那麽可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。
6) 如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
7) 盡量避免使用遊標,因為遊標的效率較差,如果遊標操作的數據超過1萬行,那麽就應該考慮改寫。
8) 盡量避免大事務操作,提高系統並發能力。
9) 盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
10) 拆分大的 DELETE 或INSERT 語句,批量提交SQL語句。
數據庫常用查詢語句寫法(優化)