優化查詢,應儘可能避免全表掃描,應該在用於檢索數據和排序數據的字段上創建索引,如where子句用於搜索,order by子句用於排序,因此在這兩個子句涉及到的字段上須要創建索引。數據庫
應該儘可能避免在where子句中使用否認的操做符,如不等於(!=或<>)、不然數據庫引擎將放棄使用索引而進行全表掃描。併發
在儘可能避免在where子句中使用或(or)做爲鏈接條件,不然數據庫引擎將放棄使用索引而進行全表掃描。
以下面的SQL語句可能會帶來性能問題ide
select id,name,age from persons where name = 'Bill' or age > 30
因爲這條SQL語句使用了or,因此數據庫引擎會進行全表掃描,爲了不全表掃描,能夠將這條SQL語句改爲下面的形式。函數
select id,name,age from persons where name = 'Bill' union all select id,name,age from persons where num = 20
select id,name,age from persons where age is null
性能
爲了不使用null,能夠設置age字段的默認值爲0,這樣就能夠經過下面的SQL語句達到一樣的結果。select id,name,age from persons where age = 0
優化
例如,下面的SQL語句執行的效率會很是低:select id,name,age from persons where name like '%John%'
code
若是真想進行模糊查詢,可使用全文檢索。orm
select id,name,age from persons age / 2 > 12
應該利用表達式變換,改爲下面的形式:select id,name,age from persons age > 2 * 12
排序
或者乾脆改爲下面的形式:select id,name,age from persons age > 24
索引
如並不推薦下面的寫法:select id, name,age from persons where age in (22,23,24)
若是數值是連續的,應該使用between,而不要用in,若是數值是不連續的,能夠分紅多個SQL,用union all鏈接查詢結果。
select id,name,age from persons where age between 22 and 24 select id,name,age from persons where age = 22 union all select id,name,age from persons where age = 26 union all select id,name,age from persons where age = 30
不使用索引的SQL語句:select id,name,age from persons where name = @name
爲了使用索引,能夠改爲下面強制使用索引的方式:select id,name,age from persons with(index(name_index)) where name = @name
其中name_index是創建在name字段上的索引名。
select id,name,age into persons1 from persons where age < 0
這樣的代碼會返回一個空結果集,並且會大量消耗系統資源,若是真的想建一個空表,應該直接用create table語句。
select id,first_name,last_name from persons where first_name = 'Bill'
select id,num from t where num in (select num from h)
應該用下面的SQL語句代替:
select id,num form t where exists(select 0 from h where num = t.num)
索引並非在任什麼時候候都有效,若是索引列有大量重複的數據,那麼數據庫引擎可能不會去利用索引。例如,sex字段的值只有兩種可能:male和female,可能這兩個值各佔一半,這樣在sex字段上創建索引就沒有任何意義。
能使用數值型字段就使用數值型字段。由於比較數值型字段的效率要遠比字符型字段的效率高,這是由於比較字符型的值,要一個字母一個字母地比較,而數值型的值,只是比較一個數。因此若是隻包含數值信息的值,應該儘可能使用數值類型的字段。例如,age、salary等。
應儘可能避免使用固定長度的字段,如char、nchar。使用可變長度的字段是一個很是好的選擇。由於可變長度字段佔用的空間是按需分配的,因此佔用空間比較少。對於查詢來講,毫無疑問,固然是佔用空間小的字段的查詢效率更高了。
select id,name,age from persons where age > 20
儘可能如要使用「」返回全部不須要的字段,也不須要一下就查詢出全部的記錄,以下面的SQL語句在數據量很大時查詢效率是很是低的。
`select from persons`
索引有利有弊,增長索引,能夠提升select的執行效率,但付出的代價是在進行insert和update操做時,可能會下降效率。由於進行insert和update操做時一般須要重建索引。因此在一個表中並非索引越多越好。個人建議以下:
(1)若是一個表大多數時進行的是select操做,那麼索引多一些大多數時候確實能夠提高性能,但這有一個前提,就是不能頻繁進行insert和update操做。
(2)一個表中的索引數不能太多,最好不要超過6個,不然就好考慮優化一下數據庫了。
應儘量的避免更新 clustered 索引數據列,由於 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將致使整個表記錄的順序的調整,會耗費至關大的資源。若應用系統須要頻繁更新 clustered 索引數據列,那麼須要考慮是否應將該索引建爲 clustered 索引。
應儘可能避免向客戶端返回大理數據,若是數據量過大,應該改變一下需求,或採用分頁返回的方式,如使用MySQL中的limit子句如今返回的數據。
儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該採用其餘方案。
使用基於遊標的方法或臨時表方法以前,應先尋找基於數據集的解決方案來解決問題,基於數據集的方法一般更有效。
若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先用 truncate table清除表中的數據 ,而後 用drop table完全刪除物理表 ,這樣能夠避免系統表的較長時間鎖定。
避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。
在新建臨時表時,若是一次性插入的數據量很大,那麼可使用 select into 代替 create table,避免形成大量 log ,以提升執行效率;若是數據量不大,爲了緩和系統表的資源,應先create table,而後使用insert插入數據。
在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送 DONE_IN_PROC 消息。
儘可能避免大事務操做,提升系統併發能力。
insert into persons(id,name,age) values('Bill',24) insert into persons(id,name,age) values('Mike',26) insert into persons(id,name,age) values('John',20)
爲了提高性能,能夠一次性插入這3條記錄。insert into persons(id,name,age) values('Bill',24),('Mike',26),('John',20)
反例:
select id,name,age from persons where name like '%abc%'
若是在關鍵字前面加%,那麼查詢是確定要走全表查詢的。
正例:select id,name,age from persons where name like 'abc%'
union和union all的差別主要是前者須要將兩個(或者多個)結果集合並後再進行惟一性過濾操做,這就會涉及到排序,增長大量的cpu運算,加大資源消耗及延遲。因此當咱們能夠確認不可能出現重複結果集或者不在意重複結果集的時候,儘可能使用union all而不是union。
29.儘可能使用等值鏈接
等值鏈接就是inner join,也稱爲內聯進,而left join和right join是外鏈接。
先看下面的SQL語句
select a.id,a.name,b.id,b.name from a left join b on a.id = b.id select a.id,a.name,b.id,b.name from a right join b on a.id = b.id select a.id,a.name,b.id,b.name from a inner join b on a.id = b.id
上面的3條SQL語句,前兩條分別使用了左鏈接和右鏈接,而最後一條使用了內鏈接,通過實際運行,使用內鏈接的SQL語句的執行效率明顯優於左鏈接和右鏈接。因此在能知足需求的前提下,應該儘量使用內鏈接(等值鏈接)。
select id,name from a where exists (select id from b where id>=10 and a.product_id=b.product_id)
在上面的SQL語句中,數據庫引擎會先對外表a執行全表查詢,而後根據product_id逐個執行子查詢,若是外層表(a表)中的數據很是多,查詢性能會很是糟糕。因此應該將SQL語句改爲下面的形式:
select id,name from a inner join b on A.product_id=b.product_id where b.id>=10