大數據量時Mysql的優化要點

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、盡量避免向客戶端返回大數據量、若數據量過大、應該考慮相應需求是否合理。

You May Also Like