MySQL性能調優

MYSQL查詢語句優化

mysql的性能優化包羅甚廣: 索引優化,查詢優化,查詢緩存,服務器設置優化,操作系統和硬件優化,應用層面優化(web服務器,緩存)等等。這里的記錄的優化技巧更適用于開發人員,都是從網絡上收集和自己整理的,主要是查詢語句上面的優化,其它層面的優化技巧在此不做記錄。

查詢的開銷指標:

執行時間 檢查的行數 返回的行數

建立索引的幾個準則:

1、合理的建立索引能夠加速數據讀取效率,不合理的建立索引反而會拖慢數據庫的響應速度。 2、索引越多,更新數據的速度越慢。 3、盡量在采用MyIsam作為引擎的時候使用索引(因為MySQL以BTree存儲索引),而不是InnoDB。但MyISAM不支持Transcation。 4、當你的程序和數據庫結構/SQL語句已經優化到無法優化的程度,而程序瓶頸并不能順利解決,那就是應該考慮使用諸如memcached這樣的分布式緩存系統的時候了。 5、習慣和強迫自己用EXPLAIN來分析你SQL語句的性能。

1. count的優化

比如:計算id大于5的城市 a. select count(*) from world.city where id > 5; b. select (select count(*) from world.city) – count(*) from world.city where id <= 5; a語句當行數超過11行的時候需要掃描的行數比b語句要多, b語句掃描了6行,此種情況下,b語句比a語句更有效率。當沒有where語句的時候直接select count(*) from world.city這樣會更快,因為mysql總是知道表的行數。

2. 避免使用不兼容的數據類型。

例如float和int、char和varchar、binary和varbinary是不兼容的。數據類型的不兼容可能使優化器無法執行一些本來可以進行的優化操作。 在程序中,保證在實現功能的基礎上,盡量減少對數據庫的訪問次數;通過搜索參數,盡量減少對表的訪問行數,最小化結果集,從而減輕網絡負擔;能夠分開的操作盡量分開處理,提高每次的響應速度;在數據窗口使用SQL時,盡量把使用的索引放在選擇的首列;算法的結構盡量簡單;在查詢時,不要過多地使用通配符如 SELECT * FROM T1語句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的情況下盡量限制盡量結果集行數如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因為某些情況下用戶是不需要那么多的數據的。不要在應用中使用數據庫游標,游標是非常有用的工具,但比使用常規的、面向集的SQL語句需要更大的開銷;按照特定順序提取數據的查找。

3. 索引字段上進行運算會使索引失效。

盡量避免在WHERE子句中對字段進行函數或表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如: SELECT * FROM T1 WHERE F1/2=100 應改為: SELECT * FROM T1 WHERE F1=100*2

4. 避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等這樣的操作符.

因為這會使系統無法使用索引,而只能直接搜索表中的數據。例如: SELECT id FROM employee WHERE id != “B%” 優化器將無法通過索引來確定將要命中的行數,因此需要搜索該表的所有行。在in語句中能用exists語句代替的就用exists.

5. 盡量使用數字型字段.

一部分開發人員和數據庫管理人員喜歡把包含數值信息的字段 設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接回逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。

6. 合理使用EXISTS,NOT EXISTS子句。如下所示:

1.SELECT SUM(T1.C1) FROM T1 WHERE (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0) 2.SELECT SUM(T1.C1) FROM T1WHERE EXISTS(SELECT * FROM T2 WHERE T2.C2=T1.C2) 兩者產生相同的結果,但是后者的效率顯然要高于前者。因為后者不會產生大量鎖定的表掃描或是索引掃描。如果你想校驗表里是否存在某條紀錄,不要用count(*)那樣效率很低,而且浪費服務器資源。可以用EXISTS代替。如: IF (SELECT COUNT(*) FROM table_name WHERE column_name = ‘xxx’)可以寫成:IF EXISTS (SELECT * FROM table_name WHERE column_name = ‘xxx’)

7. 能夠用BETWEEN的就不要用IN

8. 能夠用DISTINCT的就不用GROUP BY

9. 盡量不要用SELECT INTO語句。SELECT INTO 語句會導致表鎖定,阻止其他用戶訪問該表。

10. 必要時強制查詢優化器使用某個索引

SELECT * FROM T1 WHERE nextprocess = 1 AND processid IN (8,32,45) 改成: SELECT * FROM T1 (INDEX = IX_ProcessID) WHERE nextprocess = 1 AND processid IN (8,32,45) 則查詢優化器將會強行利用索引IX_ProcessID 執行查詢。

11. 消除對大型表行數據的順序存取

盡管在所有的檢查列上都有索引,但某些形式的WHERE子句強迫優化器使用順序存取。如: SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008 解決辦法可以使用并集來避免順序存取: SELECT * FROM orders WHERE customer_num=104 AND order_num>1001 UNION SELECT * FROM orders WHERE order_num=1008 這樣就能利用索引路徑處理查詢。【jacking 數據結果集很多,但查詢條件限定后結果集不大的情況下,后面的語句快】

12. 盡量避免在索引過的字符數據中,使用非打頭字母搜索。這也使得引擎無法利用索引。

見如下例子: SELECT * FROM T1 WHERE NAME LIKE ‘%L%’ SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’ SELECT * FROM T1 WHERE NAME LIKE ‘L%’ 即使NAME字段建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數據逐條操作來完成任務。而第三個查詢能夠使用索引來加快操作,不要習慣性的使用 ‘%L%’這種方式(會導致全表掃描),如果可以使用`L%’相對來說更好;

13. 雖然UPDATE、DELETE語句的寫法基本固定,但是還是對UPDATE語句給點建議:

a) 盡量不要修改主鍵字段。 b) 當修改VARCHAR型字段時,盡量使用相同長度內容的值代替。 c) 盡量最小化對于含有UPDATE觸發器的表的UPDATE操作。 d) 避免UPDATE將要復制到其他數據庫的列。 e) 避免UPDATE建有很多索引的列。 f) 避免UPDATE在WHERE子句條件中的列。

14. 能用UNION ALL就不要用UNION

UNION ALL不執行SELECT DISTINCT函數,這樣就會減少很多不必要的資源 在跨多個不同的數據庫時使用UNION是一個有趣的優化方法,UNION從兩個互不關聯的表中返回數據,這就意味著不會出現重復的行,同時也必須對數據進行排序,我們知道排序是非常耗費資源的,特別是對大表的排序。 UNION ALL可以大大加快速度,如果你已經知道你的數據不會包括重復行,或者你不在乎是否會出現重復的行,在這兩種情況下使用UNION ALL更適合。此外,還可以在應用程序邏輯中采用某些方法避免出現重復的行,這樣UNION ALL和UNION返回的結果都是一樣的,但UNION ALL不會進行排序。

15. 字段數據類型優化:

a. 避免使用NULL類型:NULL對于大多數數據庫都需要特殊處理,MySQL也不例外,它需要更多的代碼,更多的檢查和特殊的索引邏輯,有些開發人員完全沒有意識到,創建表時NULL是默認值,但大多數時候應該使用NOT NULL,或者使用一個特殊的值,如0,-1作為默認值。 b. 盡可能使用更小的字段,MySQL從磁盤讀取數據后是存儲到內存中的,然后使用cpu周期和磁盤I/O讀取它,這意味著越小的數據類型占用的空間越小,從磁盤讀或打包到內存的效率都更好,但也不要太過執著減小數據類型,要是以后應用程序發生什么變化就沒有空間了。修改表將需要重構,間接地可能引起代碼的改變,這是很頭疼的問題,因此需要找到一個平衡點。 c. 優先使用定長型

16. 關于大數據量limit分布的優化見下面鏈接(當偏移量特別大時,limit效率會非常低):

http://ariyue.iteye.com/blog/553541附上一個提高limit效率的簡單技巧,在覆蓋索引(覆蓋索引用通俗的話講就是在select的時候只用去讀取索引而取得數據,無需進行二次select相關表)上進行偏移,而不是對全行數據進行偏移。可以將從覆蓋索引上提取出來的數據和全行數據進行聯接,然后取得需要的列,會更有效率,看看下面的查詢: mysql> select film_id, description from sakila.film order by title limit 50, 5; 如果表非常大,這個查詢最好寫成下面的樣子: mysql> select film.film_id, film.description from sakila.film inner join(select film_id from sakila.film order by title liimit 50,5) as film usinig(film_id);

17. 程序中如果一次性對同一個表插入多條數據,比如以下語句:

insert into person(name,age) values(‘xboy’, 14); insert into person(name,age) values(‘xgirl’, 15); insert into person(name,age) values(‘nia’, 19); 把它拼成一條語句執行效率會更高. insert into person(name,age) values(‘xboy’, 14), (‘xgirl’, 15),(‘nia’, 19);

18.不要在選擇的欄位上放置索引,這是無意義的。應該在條件選擇的語句上合理的放置索引,比如where,order by。

SELECT id,title,content,cat_id FROM article WHERE cat_id = 1;

上面這個語句,你在id/title/content上放置索引是毫無意義的,對這個語句沒有任何優化作用。但是如果你在外鍵cat_id上放置一個索引,那作用就相當大了。

19.ORDER BY語句的MySQL優化:a. ORDER BY + LIMIT組合的索引優化。如果一個SQL語句形如:

SELECT [column1],[column2],…. FROM [TABLE] ORDER BY [sort] LIMIT [offset],[LIMIT];

這個SQL語句優化比較簡單,在[sort]這個欄位上建立索引即可。

b. WHERE + ORDER BY + LIMIT組合的索引優化,形如:

SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] = [VALUE] ORDER BY [sort] LIMIT [offset],[LIMIT];

這個語句,如果你仍然采用第一個例子中建立索引的方法,雖然可以用到索引,但是效率不高。更高效的方法是建立一個聯合索引(columnX,sort)

c. WHERE + IN + ORDER BY + LIMIT組合的索引優化,形如:

SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] IN ([value1],[value2],…) ORDER BY [sort] LIMIT [offset],[LIMIT];

這個語句如果你采用第二個例子中建立索引的方法,會得不到預期的效果(僅在[sort]上是using index,WHERE那里是using where;using filesort),理由是這里對應columnX的值對應多個。 目前哥還木有找到比較優秀的辦法,等待高手指教。

d.WHERE+ORDER BY多個欄位+LIMIT,比如:

SELECT * FROM [table] WHERE uid=1 ORDER x,y LIMIT 0,10;

對于這個語句,大家可能是加一個這樣的索引:(x,y,uid)。但實際上更好的效果是(uid,x,y)。這是由MySQL處理排序的機制造成的。

20. 其它技巧:

http://www.cnblogs.com/nokiaguy/archive/2008/05/24/1206469.htmlhttp://www.cnblogs.com/suchshow/archive/2011/12/15/2289182.htmlhttp://www.cnblogs.com/cy163/archive/2009/05/28/1491473.htmlhttp://www.cnblogs.com/younggun/articles/1719943.htmlhttp://wenku.baidu.com/view/f57c7041be1e650e52ea9985.html

最后,你可以使用explain關鍵字去判斷和評測一個sql語句是否還有優化的可能性,關于它的詳細使用請參考mysql手冊。

參考資料:https://www.cnblogs.com/wangning528/p/6388538.html

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • MYSQL 基礎知識 1 MySQL數據庫概要 2 簡單MySQL環境 3 數據的存儲和獲取 4 MySQL基本操...
    Kingtester閱讀 7,830評論 5 116
  • 轉 # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,758評論 0 44
  • MySQL性能調優 索引 索引是什么 官方介紹索引是幫助MySQL高效獲取數據的數據結構。筆者理解索引相當于一本書...
    陳小陌丿閱讀 1,420評論 0 4
  • 艷芳酷愛面畫,中學時,在課本和作業本上常畫些小動物、小笑臉什么的,栩栩如生。大前天借消暑之機,臨摹了兩幅圖...
    LBR_5f68閱讀 284評論 0 0
  • 中午約老姐過來拿東西,順便一起吃午餐,感覺很久沒出去吃過飯了,現在每天都踏著點下班就匆忙趕回家,周末因為家有老小,...
    winzy小文子閱讀 191評論 0 1