MySQL語句優化常見誤區與優化技巧
原文鏈接:http://www.2cto.com/database/201303/195666.html
1 常見誤區
誤區1:count(1)和count(primary_key)優於count(*)
誤區2:count(*)和count(column)是一樣的
count(*)表示整個結果集有多少記錄
count(column)表示結果集中有多少個column字段不爲空的記錄
誤區3:select a,b from …比select a,b,c from …可以讓數據庫訪問更少的數據量
大多數關係型數據庫都是按照行方式存儲,而數據存取操作都是以一個固定大小的IO單元爲單位,大多數時候每個IO單元存儲了多少行,每行都是存儲了該行的所有字段(lob等特殊類型字段除外)。例外情況是我們的這個查詢在索引中就可以完成,也就是當只取a,b兩個字段的時候不需要回表,而c這個字段不在使用的索引中,需要回表取得數據,二者的IO量會有較大差異(覆蓋索引)。
誤區4:order by 一定要做排序操作
索引數據時有序的,如果所需要的數據和某個索引順序一致,而且查詢又通過該索引執行,那麼數據庫一般會省略排序操作。
誤區5:執行計劃中有filesort就會進行磁盤文件排序
2 語句優化技巧
1)儘量少join
2)儘量少排序
減少排序的方法:
l 通過利用索引來排序
l 減少參與排序的記錄條數
l 非必要不對數據進行排序
l ……
3)儘量避免select *
當查詢結果僅僅只需要在索引中就能找到的時候,會極大減少IO量的。
4)儘量用join代替子查詢
MySQL的子查詢執行計劃一直存在較大問題
5)儘量少or
6)儘量用union all代替union
union 和union all的差異主要是前者需要將兩個(或者多個)結果集合並後再進行唯一性過濾操作,這就會涉及到排序,增加大量的CPU運算,加大資源消耗延遲。
7)儘量早過濾
8)避免類型轉換
本處所述的類型轉換是指where子句中出現column字段的類型和傳入的參數類型不一致的時候發生的類型轉換。人爲進行此種類型轉換,直接導致MySQL無法使用索引。
9)優先優化高併發的SQL,而不是執行頻率低某些“大”SQL
10)從全局出發,而不是片面調整
儘可能對每一條運行在數據庫中的SQL進行explain
原文鏈接:http://blog.sina.com.cn/s/blog_95ee143401013gzf.html
11)避免使用不兼容的數據類型
儘量減少對數據庫的訪問次數
儘量減少對錶的訪問行數,最小化結果集,從而減輕網絡負擔
在數據窗口使用SQL時,儘量把使用的索引放在選擇的首列
12)索引字段上進行運算會使索引失效
儘量避免在where子句中對字段進行函數或表達式操作
SELECT * FROM T1 WHERE F1/2=100應改爲
SELECT * FROM T1 WHERE F1=100*2
13)避免使用!=或<>、IS NULL或IS NOT NULL、IN、NOT IN等這樣的操作符
14)儘量使用數字型字段
15)合理使用EXISTS、NOT EXISTS子句
1、SELECT SUM(T1,C1) FROM T1 WHERE (SELECT COUNT(*) FROM T2 WHERET2.C2=T1.C2>0)
2、SELECT SUM(T1,C1) FROM T1 WHERE EXISTS(SELECT * FROM T2 WHERET2.C2=T1.C2)
兩者產生相同的結果,但是後者的效率顯然高於前者,因爲後者不會產生大量鎖定的表掃描或是索引掃描。如果想校驗表裏是否存在某條記錄,不要用count(*),可以用EXISTS代替。
16)能夠用BETWEEN的就不用IN
17)能夠用DISTINCT的就不用GROUP BY
18)儘量不要用SELECT INTO語句,SELECT INTO語句會導致表鎖定,阻止其他用戶訪問該表
19)必要時強制查詢優化器使用某個索引
SELECT * FROM T1 WHERE nextprocess=1 AND processidIN (8,32,45)改成
SELECT * FROM T1 (INDEX = IX_ProcessID)WHERE nextprocess =1 AND processid IN (8,32,45)
則查詢優化器將會強行利用索引IX_ProcessID執行查詢
20)消除對大型錶行數據的順序存取
21)儘量避免在索引過的字符數據中,使用非打頭字母搜索。這也使得引擎無法利用索引
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’
SELECT * FROM T1 WHERE SUBSTRING(NAME,2,1)=’L’
SELECT * FROM T1 WHERE NAME LIKE ‘L%’
即使NAME字段建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數據逐條操作來完成任務,而第三個查詢能夠使用索引來加快操作,不要習慣性的使用’%L%’這種方式(會導致全表掃描),如果可以使用’L%’相對來說更好
22)關於update語句的建議
l 儘量不要修改主鍵字段
l 當修改varchar型字段時,儘量使用相同長度內容的值代替
l 儘量最小化對於含有update觸發器的表的update操作
l 避免update將要複製到其他數據庫的列
l 避免update建有很多索引的列
l 避免update在where子句條件中的列
23)程序中如果一次性對同一個表插入多條數據時,可以將其拼成一條語句執行效率會更高
insert into student(sid,sname) values (11,’zhangsan’);
insert into student(sid,sname) values (12,’lisi’);
insert into student(sid,sname) values (13,’liqin’);
insert into student(sid,sname) values (11,’zhangsan’),(12,’lisi’),(13,’liqin’);
24)不要在選擇的欄位上放置索引,應該在條件選擇的語句上合理的放置索引
SELECT id,title,content,cat_id FROM articleWHERE cat_id=1;
上面這個語句,在id/title/content上放置索引是毫無意義的,對這個語句沒有任何優化作用,但是如果在外鍵cat_id上放置一個索引,作用就相當大。
轉載請註明出處:MySQL語句優化常見誤區與優化技巧