千萬級MySQL數據庫建立索引,提高性能的秘訣

實踐中如何優化MySQL

實踐中,MySQL的優化主要涉及SQL語句及索引的優化、數據表結構的優化、系統配置的優化和硬件的優化四個方面,如下圖所示:

SQL語句及索引的優化

SQL語句的優化

SQL語句的優化主要包括三個問題,即如何發現有問題的SQL、如何分析SQL的執行計劃以及如何優化SQL,下面將逐一解釋。

怎么發現有問題的SQL?(通過MySQL慢查詢日志對有效率問題的SQL進行監控)

MySQL的慢查詢日志是MySQL提供的一種日志記錄,它用來記錄在MySQL中響應時間超過閥值的語句,具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢日志中。

long_query_time的默認值為10,意思是運行10s以上的語句。慢查詢日志的相關參數如下所示:

通過MySQL的慢查詢日志,我們可以查詢出執行的次數多占用的時間長的SQL、可以通過pt_query_disgest(一種mysql慢日志分析工具)分析Rows examine(MySQL執行器需要檢查的行數)項去找出IO大的SQL以及發現未命中索引的SQL,對于這些SQL,都是我們優化的對象。

通過explain查詢和分析SQL的執行計劃

使用 EXPLAIN 關鍵字可以知道MySQL是如何處理你的SQL語句的,以便分析查詢語句或是表結構的性能瓶頸。通過explain命令可以得到表的讀取順序、數據讀取操作的操作類型、哪些索引可以使用、哪些索引被實際使用、表之間的引用以及每張表有多少行被優化器查詢等問題。當擴展列extra出現Using filesort和Using temporay,則往往表示SQL需要優化了。

優化SQL語句

優化insert語句:一次插入多值;

應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描;

應盡量避免在 where 子句中對字段進行null值判斷,否則將導致引擎放棄使用索引而進行全表掃描;

優化嵌套查詢:子查詢可以被更有效率的連接(Join)替代;

很多時候用 exists 代替 in 是一個好的選擇。


索引優化

建議在經常作查詢選擇的字段、經常作表連接的字段以及經常出現在order by、group by、distinct 后面的字段中建立索引。但必須注意以下幾種可能會引起索引失效的情形:

以“%(表示任意0個或多個字符)”開頭的LIKE語句,模糊匹配;

OR語句前后沒有同時使用索引;

數據類型出現隱式轉化(如varchar不加單引號的話可能會自動轉換為int型);

對于多列索引,必須滿足最左匹配原則(eg,多列索引col1、col2和col3,則 索引生效的情形包括col1或col1,col2或col1,col2,col3)。


數據庫表結構的優化

數據庫表結構的優化包括選擇合適數據類型、表的范式的優化、表的垂直拆分和表的水平拆分等手段。


選擇合適數據類型

使用較小的數據類型解決問題;

使用簡單的數據類型(mysql處理int要比varchar容易);

盡可能的使用not null 定義字段;

盡量避免使用text類型,非用不可時最好考慮分表;


表的范式的優化

一般情況下,表的設計應該遵循三大范式。


表的垂直拆分

把含有多個列的表拆分成多個表,解決表寬度問題,具體包括以下幾種拆分手段:

把不常用的字段單獨放在同一個表中;

把大字段獨立放入一個表中;

把經常使用的字段放在一起;

這樣做的好處是非常明顯的,具體包括:拆分后業務清晰,拆分規則明確、系統之間整合或擴展容易、數據維護簡單。


表的水平拆分

表的水平拆分用于解決數據表中數據過大的問題,水平拆分每一個表的結構都是完全一致的。一般地,將數據平分到N張表中的常用方法包括以下兩種:

對ID進行hash運算,如果要拆分成5個表,mod(id,5)取出0~4個值;

針對不同的hashID將數據存入不同的表中;

表的水平拆分會帶來一些問題和挑戰,包括跨分區表的數據查詢、統計及后臺報表的操作等問題,但也帶來了一些切實的好處:

表分割后可以降低在查詢時需要讀的數據和索引的頁數,同時也降低了索引的層數,提高查詢速度;

表中的數據本來就有獨立性,例如表中分別記錄各個地區的數據或不同時期的數據,特別是有些數據常用,而另外一些數據不常用。

需要把數據存放到多個數據庫中,提高系統的總體可用性(分庫,雞蛋不能放在同一個籃子里)。


系統配置的優化

操作系統配置的優化:增加TCP支持的隊列數

mysql配置文件優化:Innodb緩存池設置(innodb_buffer_pool_size,推薦總內存的75%)和緩存池的個數(innodb_buffer_pool_instances)


硬件的優化

CPU:核心數多并且主頻高的 內存:增大內存 磁盤配置和選擇:磁盤性能


MySQL中的悲觀鎖與樂觀鎖的實現

悲觀鎖與樂觀鎖是兩種常見的資源并發鎖設計思路,也是并發編程中一個非常基礎的概念。


悲觀鎖

悲觀鎖的特點是先獲取鎖,再進行業務操作,即“悲觀”的認為所有的操作均會導致并發安全問題,因此要先確保獲取鎖成功再進行業務操作。通常來講,在數據庫上的悲觀鎖需要數據庫本身提供支持,即通過常用的select … for update操作來實現悲觀鎖。當數據庫執行select … for update時會獲取被select中的數據行的行鎖,因此其他并發執行的select … for update如果試圖選中同一行則會發生排斥(需要等待行鎖被釋放),因此達到鎖的效果。select for update獲取的行鎖會在當前事務結束時自動釋放,因此必須在事務中使用。    這里需要特別注意的是,不同的數據庫對select… for update的實現和支持都是有所區別的,例如oracle支持select for update no wait,表示如果拿不到鎖立刻報錯,而不是等待,mysql就沒有no wait這個選項。另外,mysql還有個問題是: select… for update語句執行中所有掃描過的行都會被鎖上,這一點很容易造成問題。因此,如果在mysql中用悲觀鎖務必要確定使用了索引,而不是全表掃描。


樂觀鎖

樂觀鎖的特點先進行業務操作,只在最后實際更新數據時進行檢查數據是否被更新過,若未被更新過,則更新成功;否則,失敗重試。樂觀鎖在數據庫上的實現完全是邏輯的,不需要數據庫提供特殊的支持。一般的做法是在需要鎖的數據上增加一個版本號或者時間戳,然后按照如下方式實現:

SELECT data AS old_data, version AS old_version FROM …;

//根據獲取的數據進行業務操作,得到new_data和new_version

UPDATE SET data = new_data, version = new_version WHERE version = old_version

if (updated row > 0) {

// 樂觀鎖獲取成功,操作完成

} else {

// 樂觀鎖獲取失敗,回滾并重試

}

樂觀鎖是否在事務中其實都是無所謂的,其底層機制是這樣:在數據庫內部update同一行的時候是不允許并發的,即數據庫每次執行一條update語句時會獲取被update行的寫鎖,直到這一行被成功更新后才釋放。因此在業務操作進行前獲取需要鎖的數據的當前版本號,然后實際更新數據時再次對比版本號確認與之前獲取的相同,并更新版本號,即可確認這其間沒有發生并發的修改。如果更新失敗,即可認為老版本的數據已經被并發修改掉而不存在了,此時認為獲取鎖失敗,需要回滾整個業務操作并可根據需要重試整個過程。


悲觀鎖與樂觀鎖的應用場景

一般情況下,讀多寫少更適合用樂觀鎖,讀少寫多更適合用悲觀鎖。樂觀鎖在不發生取鎖失敗的情況下開銷比悲觀鎖小,但是一旦發生失敗回滾開銷則比較大,因此適合用在取鎖失敗概率比較小的場景,可以提升系統并發性能。


MySQL存儲引擎中的MyISAM和InnoDB區別詳解

在MySQL 5.5之前,MyISAM是mysql的默認數據庫引擎,其由早期的ISAM(Indexed Sequential Access Method:有索引的順序訪問方法)所改良。雖然MyISAM性能極佳,但卻有一個顯著的缺點: 不支持事務處理。不過,MySQL也導入了另一種數據庫引擎InnoDB,以強化參考完整性與并發違規處理機制,后來就逐漸取代MyISAM。

InnoDB是MySQL的數據庫引擎之一,其由Innobase oy公司所開發,2006年五月由甲骨文公司并購。與傳統的ISAM、MyISAM相比,InnoDB的最大特色就是支持ACID兼容的事務功能,類似于PostgreSQL。目前InnoDB采用雙軌制授權,一是GPL授權,另一是專有軟件授權。具體地,MyISAM與InnoDB作為MySQL的兩大存儲引擎的差異主要包括:

存儲結構:每個MyISAM在磁盤上存儲成三個文件:第一個文件的名字以表的名字開始,擴展名指出文件類型。.frm文件存儲表定義,數據文件的擴展名為.MYD (MYData),索引文件的擴展名是.MYI (MYIndex)。InnoDB所有的表都保存在同一個數據文件中(也可能是多個文件,或者是獨立的表空間文件),InnoDB表的大小只受限于操作系統文件的大小,一般為2GB。

存儲空間:MyISAM可被壓縮,占據的存儲空間較小,支持靜態表、動態表、壓縮表三種不同的存儲格式。InnoDB需要更多的內存和存儲,它會在主內存中建立其專用的緩沖池用于高速緩沖數據和索引。

可移植性、備份及恢復:MyISAM的數據是以文件的形式存儲,所以在跨平臺的數據轉移中會很方便,同時在備份和恢復時也可單獨針對某個表進行操作。InnoDB免費的方案可以是拷貝數據文件、備份 binlog,或者用 mysqldump,在數據量達到幾十G的時候就相對痛苦了。

事務支持:MyISAM強調的是性能,每次查詢具有原子性,其執行數度比InnoDB類型更快,但是不提供事務支持。InnoDB提供事務、外鍵等高級數據庫功能,具有事務提交、回滾和崩潰修復能力。

AUTO_INCREMENT:在MyISAM中,可以和其他字段一起建立聯合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,它可以根據前面幾列進行排序后遞增。InnoDB中必須包含只有該字段的索引,并且引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。

表鎖差異:MyISAM只支持表級鎖,用戶在操作MyISAM表時,select、update、delete和insert語句都會給表自動加鎖,如果加鎖以后的表滿足insert并發的情況下,可以在表的尾部插入新的數據。InnoDB支持事務和行級鎖。行鎖大幅度提高了多用戶并發操作的新能,但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。

全文索引:MyISAM支持 FULLTEXT類型的全文索引;InnoDB不支持FULLTEXT類型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。

表主鍵:MyISAM允許沒有任何索引和主鍵的表存在,索引都是保存行的地址。對于InnoDB,如果沒有設定主鍵或者非空唯一索引,就會自動生成一個6字節的主鍵(用戶不可見),數據是主索引的一部分,附加索引保存的是主索引的值。

表的具體行數:MyISAM保存表的總行數,select count() from table;會直接取出出該值;而InnoDB沒有保存表的總行數,如果使用select count() from table;就會遍歷整個表,消耗相當大,但是在加了wehre條件后,myisam和innodb處理的方式都一樣。

CURD操作:在MyISAM中,如果執行大量的SELECT,MyISAM是更好的選擇。對于InnoDB,如果你的數據執行大量的INSERT或UPDATE,出于性能方面的考慮,應該使用InnoDB表。DELETE從性能上InnoDB更優,但DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除,在innodb上如果要清空保存有大量數據的表,最好使用truncate table這個命令。

外鍵:MyISAM不支持外鍵,而InnoDB支持外鍵。

通過上述的分析,基本上可以考慮使用InnoDB來替代MyISAM引擎了,原因是InnoDB自身很多良好的特點,比如事務支持、存儲過程、視圖、行級鎖、外鍵等等。尤其在并發很多的情況下,相信InnoDB的表現肯定要比MyISAM強很多。另外,必須需要注意的是,任何一種表都不是萬能的,合適的才是最好的,才能最大的發揮MySQL的性能優勢。如果是不復雜的、非關鍵的Web應用,還是可以繼續考慮MyISAM的,這個具體情況具體考慮。

MyISAM:不支持事務,不支持外鍵,表鎖;插入數據時鎖定整個表,查行數時無需整表掃描。主索引數據文件和索引文件分離;與主索引無區別;

InnoDB:支持事務,外鍵,行鎖,查表總行數時,全表掃描;主索引的數據文件本身就是索引文件;輔助索引記錄主鍵的值;


MySQL鎖類型

根據鎖的類型分,可以分為共享鎖,排他鎖,意向共享鎖和意向排他鎖。

根據鎖的粒度分,又可以分為行鎖,表鎖。

對于mysql而言,事務機制更多是靠底層的存儲引擎來實現,因此,mysql層面只有表鎖,而支持事務的innodb存 儲引擎則實現了行鎖(記錄鎖(在行相應的索引記錄上的鎖)),gap鎖(是在索引記錄間歇上的鎖),next-key鎖(是記錄鎖和在此索引記錄之前的gap上的鎖的結合)。Mysql的記錄鎖實質是索引記錄的鎖,因為innodb是索引組織表;gap鎖是索引記錄間隙的鎖,這種鎖只在RR隔離級別下有效;next-key鎖是記錄鎖加上記錄之前gap鎖的組合。mysql通過gap鎖和next-key鎖實現RR隔離級別。

說明:對于更新操作(讀不上鎖),只有走索引才可能上行鎖;否則會對聚簇索引的每一行上寫鎖,實際等同于對表上寫鎖。    若多個物理記錄對應同一個索引,若同時訪問,也會出現鎖沖突;

當表有多個索引時,不同事務可以用不同的索引鎖住不同的行,另外innodb會同時用行鎖對數據記錄(聚簇索引)加鎖。

MVCC(多版本并發控制)并發控制機制下,任何操作都不會阻塞讀操作,讀操作也不會阻塞任何操作,只因為讀不上鎖。    共享鎖:由讀表操作加上的鎖,加鎖后其他用戶只能獲取該表或行的共享鎖,不能獲取排它鎖,也就是說只能讀不能寫

排它鎖:由寫表操作加上的鎖,加鎖后其他用戶不能獲取該表或行的任何鎖,典型是mysql事務中的更新操作。

意向共享鎖(IS):事務打算給數據行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。

意向排他鎖(IX):事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。


數據庫死鎖概念

多數情況下,可以認為如果一個資源被鎖定,它總會在以后某個時間被釋放。而死鎖發生在當多個進程訪問同一數據庫時,其中每個進程擁有的鎖都是其他進程所需的,由此造成每個進程都無法繼續下去。簡單的說,進程A等待進程B釋放他的資源,B又等待A釋放他的資源,這樣就互相等待就形成死鎖。

雖然進程在運行過程中,可能發生死鎖,但死鎖的發生也必須具備一定的條件,死鎖的發生必須具備以下四個必要條件:

1)互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程占用。如果此時還有其它進程請求資源,則請求者只能等待,直至占有資源的進程用畢釋放。    2)請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。    3)不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。    4)環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,???,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。    下列方法有助于最大限度地降低死鎖:

按同一順序訪問對象。

避免事務中的用戶交互。

保持事務簡短并在一個批處理中。

使用低隔離級別。

使用綁定連接。

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

推薦閱讀更多精彩內容

  • 一、MySQL優化 MySQL優化從哪些方面入手: (1)存儲層(數據) 構建良好的數據結構。可以大大的提升我們S...
    寵辱不驚丶歲月靜好閱讀 2,454評論 1 8
  • 今天看到一位朋友寫的mysql筆記總結,覺得寫的很詳細很用心,這里轉載一下,供大家參考下,也希望大家能關注他原文地...
    信仰與初衷閱讀 4,746評論 0 30
  • msyql -uroot -p123456 msyqladmin -uroot -p123456 GPG keys...
    nhsf閱讀 1,382評論 0 0
  • 文章導讀: 累兮,累兮,要死兮...... 本文解決問題: 1、表級鎖定(讀鎖、寫鎖) 2、行級鎖定(共享鎖、排他...
    創造new_world閱讀 645評論 0 1
  • 索引 數據庫中的查詢操作非常普遍,索引就是提升查找速度的一種手段 索引的類型 從數據結構角度分 1.B+索引:傳統...
    一凡呀閱讀 2,982評論 0 8