本文根據阿裡雲資深dba專家羅龍九在首屆阿裡巴巴線上峰會的《雲資料庫十大經典案例分析》的分享整理而成。羅龍九以mysql資料庫為例,分析了自rds成立至今,使用者在使用rds過程中最常見的問題,包括:索引、sql優化、鎖、延遲、參數優化、連接配接數、cpu、iops、磁盤、記憶體等。羅龍九通過對十大經典案例的總結,還原問題原貌,給出分析問題的思路,旨在幫助使用者在使用rds的路上少一些彎路,多一些從容。
<b>直播視訊</b>

(點選圖檔檢視視訊)
以下為整理内容。
案例一:索引
今天之是以将索引放在第一位進行分享,是因為索引的問題出現頻率是最高的。常見的索引問題包括:無索引、隐式轉換兩類。其中隐式轉換是由sql傳入的值和表結構定義的資料類型不一緻引起;或者是表字段定義的collation不一緻導緻多表join的時候出現隐式轉換。無索引的情況會導緻全表掃描;隐式轉換會導緻索引無法正常使用。
在使用索引時,我們可以通過explain(extended)檢視sql的執行計劃,判斷是否使用了索引以及發生了隐式轉換。由于常見的隐式轉換是由字段資料類型以及collation定義不當導緻,是以我們在設計開發階段,要避免資料庫字段定義,避免出現隐式轉換。此外,由于mysql不支援函數索引,在開發時要避免在查詢條件加入函數,例如date(gmt_create)。最後,所有上線的sql都要經過嚴格的稽核,建立合适的索引。
案例二:sql優化
sql優化是很多使用者都需要面對的問題。我們在不斷地優化、調試過程中總結了三類sql優化的最佳實踐,分别是分頁優化、子查詢優化、查詢需要的字段。
<b>分頁優化</b>
這條語句是普通的limit m、n的翻頁寫法,在越往後翻頁的過程中速度越慢,這是由于mysql會讀取表m+n條資料,m越大,性能越差。
我們通過采用高效的limit寫法,可以将上述語句改寫成:
進而避免分頁查詢給資料庫帶來性能影響。需要注意一點是,這裡需要在t表的sellerid字段上建立索引,id為表的主鍵。
<b>子查詢優化</b>
子查詢在mysql5.1、5.5版本中都存在較大的風險。這是一段典型子查詢sql代碼:
由于mysql的處理邏輯是周遊employees表中的每一條記錄,代入到子查詢中去 。是以當外層employees表越大時,循環次數也随之增多,進而導緻資料庫性能的下降。
這是我們改寫子查詢之後的sql代碼:
首先将子查詢的結果放到臨時表内,再去和employees表做關聯。此外,使用者也可以選擇使用mysql 5.6的版本,避免麻煩的子查詢改寫。
<b>查詢需要的字段</b>
在通路資料庫時,應該盡量避免使用select *查詢所有字段資料,隻查詢需要的字段資料。
案例三:鎖
在使用資料庫時,每個人或多或少都會碰到鎖的問題。在設計開發階段,我們需要注意這三點問題:一是避免使用myisam存儲引擎,改用innodb引擎;二是注意避免大事務,這是因為長事務導緻事務在資料庫中的運作時間加長,造成鎖等待;三是選擇将資料庫更新到支援online ddl的mysql 5.6版本。
在管理運維階段,我們可以從四點出發搞定鎖的問題:
在業務低峰期執行上述操作,比如建立索引,添加字段;
在結構變更前,觀察資料庫中是否存在長sql,大事務;
結構變更期間,監控資料庫的線程狀态是否存在lock wait;
rds支援在ddl變更中加入 wait timeout。
案例四:延遲
由于資料庫架構大多是主備的方式,延遲便成了一個常見的問題。産生延遲的原因有很多,例如在隻讀執行個體架構中,主備節點間mysql原生複制實作資料同步方式會天然導緻延遲的産生。此外,create index、repair等常見ddl操作、大事務、mdl鎖以及資源問題都會導緻延遲的出現。
處理延遲問題,需要具有清晰的排除思路:一看資源是否達到瓶頸;二看線程狀态是否有鎖;三判斷是否存在大事務。同時我們還可以通過使用innodb存儲引擎、将大事務拆分為小事務、ddl變更期間觀察是否有大查詢等具體最佳實踐降低延遲。
案例五:參數優化
我們曾經遇到這樣一個案例,某金融客戶在将本地的業務系統遷移上雲後,在最高配置的rds上運作時間明顯要比線下自建資料庫運作時間慢1倍,進而導緻客戶系統出現割接延期的風險。對于這類案例的分析,根據以往的經驗,可以從以下三點出發:
首先檢視資料庫是否是跨平台遷移(pg->mysql、oralce->mysql);
其次檢視是否是跨版本更新(mysql:5.1->5.5、5.5->5.6),不同的版本之間是有差異的;
如果上述兩點都不存在,則需要檢視具體的執行計劃、優化器、參數配置、硬體配置。
如果sql從雲下遷移到雲上或者從一個版本遷移到另一個版本的過程中出現性能問題時,要保持清晰的排查思路:從sql執行計劃到資料庫版本和優化器規則,再到參數(包括query_cache_size、temp_table_size)配置和硬體配置等一一進行排查。曾經看到這樣一個案例,一個使用者使用預設的mysql配置跑線上應用,db所在的主機的記憶體有500g,但是配置設定給mysql的記憶體确是預設的128m,導緻了整個系統的性能下降。
案例六:cpu 100%最佳實踐
導緻cpu 100%的三大因素分别是:慢sql、鎖和資源。對于慢sql問題:我們可以通過優化索引或者通過避免子查詢、隐式轉換以及進行分頁改寫等措施從根上解決該問題。對于鎖等待問題:可以通過設計開發和管理運維優化鎖等待。對于資源問題:可以通過參數優化、彈性更新、讀寫分離、資料庫拆分等方式優化。
案例七:conm 100%
導緻conm 100%的三大因素分别是慢sql、鎖、配置。對于慢sql問題:解決方案類似于處理cpu 100%,同樣是通過優化索引或者通過避免子查詢、隐式轉換以及進行分頁改寫等措施從根上解決該問題。對于鎖等待問題:同樣可以通過設計開發和管理運維優化鎖等待。對于配置問題:我們需要合理規劃資料庫上的連接配接數的使用,避免用戶端連接配接池參數配置超過執行個體最大連接配接數的情況出現。此外,還可以通過彈性更新rds的規格配置來滿足用戶端需要的連接配接數。
案例八:iops 100%
iops 100%也是一個很常見的問題。導緻iops 100%的原因也可以分為慢sql問題、ddl、配置問題三類。對于慢sql問題:解決方案同樣類似于處理cpu 100%問題,通過優化索引或者通過避免子查詢、隐式轉換以及進行分頁改寫等措施從根上解決該問題。對于ddl問題:一定要避免并發進行create index、optimze table、alter table add column等操作;同時這些操作最好在業務低峰期進行。對于配置問題:可以通過彈性更新rds的規格配置解決。
案例九:disk 100%
磁盤空間由資料檔案、日志檔案和臨時檔案組成。對于資料空間問題:由于資料檔案的索引和資料是放在一起的,當對表删除資料後可以采用optimize table收縮表空間,同時删除不必要的索引;對于寫多讀少的應用,可以使用tokudb壓縮引擎進行表壓縮。對于日志空間問題:首先我們需要減少大字段的使用;其次可以使用truncate替代delete from。對于臨時空間問題:一是可以适當地調大sort_buffer_size;二是可以建立合适索引避免排序。
案例十:mem 100%
當記憶體使用率達到100%時,作業系統會kill掉mysql程序,進而導緻業務的中斷。是以,我們需要明确地了解資料庫的記憶體使用詳情。資料庫記憶體主要由buffer pool size 、dictionary memory、thread cost memory三部分組成。對于buffer pool size問題:首先,我們可以通過建立合适的索引,避免大量的資料掃描;其次,我們需要去除不必要的索引,降低記憶體的消耗。對于thread cost memory問題:一方面,我們可以通過建立合适的索引避免排序;另一方面,在查詢資料時,我們隻查詢應用所需的資料,避免所有資料的查詢。對于dictionary memory問題:當表被通路打開後其中繼資料資訊是存儲在dictionary memory之中的,過度的分表會導緻記憶體的大量占用,是以分表時要注意把握分寸,不多過度分表,曾經看到一個資料庫中建立了十幾萬張表。
<b>關于分享嘉賓:</b>
羅龍九,阿裡雲資深dba專家,有着豐厚的dba經驗,經曆阿裡曆年雙11考驗,負責阿裡雲rds線上穩定以及專家服務團隊,積累了6年對阿裡雲資料庫使用者的運維、調優、診斷等豐富的經驗。