連接:https://www.zhihu.com/question/19719997/answer/81930332
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
不少人第一反應是各類切分;我給的順序是:
第一優化你的sql和索引;mysql
第二加緩存,memcached,redis;redis
第三以上都作了後,仍是慢,就作主從複製或主主複製,讀寫分離,能夠在應用層作,效率高,也能夠用三方工具,第三方工具推薦360的atlas,其它的要麼效率不高,要麼沒人維護;sql
第四若是以上都作了仍是慢,不要想着去作切分,mysql自帶分區表,先試試這個,對你的應用是透明的,無需更改代碼,可是sql語句是須要針對分區表作優化的,sql條件中要帶上分區條件的列,從而使查詢定位到少許的分區上,不然就會掃描所有分區,另外分區表還有一些坑,在這裏就很少說了;數據庫
第五若是以上都作了,那就先作垂直拆分,其實就是根據你模塊的耦合度,將一個大的系統分爲多個小的系統,也就是分佈式系統;緩存
第六纔是水平切分,針對數據量大的表,這一步最麻煩,最能考驗技術水平,要選擇一個合理的sharding key,爲了有好的查詢效率,表結構也要改動,作必定的冗餘,應用也要改,sql中儘可能帶sharding key,將數據定位到限定的表上去查,而不是掃描所有的表;併發
mysql數據庫通常都是按照這個步驟去演化的,成本也是由低到高;分佈式
有人也許要說第一步優化sql和索引這還用說嗎?的確,你們都知道,可是不少狀況下,這一步作的並不到位,甚至有的只作了根據sql去建索引,根本沒對sql優化(中槍了沒?),除了最簡單的增刪改查外,想實現一個查詢,能夠寫出不少種查詢語句,不一樣的語句,根據你選擇的引擎、表中數據的分佈狀況、索引狀況、數據庫優化策略、查詢中的鎖策略等因素,最終查詢的效率相差很大;優化要從總體去考慮,有時你優化一條語句後,其它查詢反而效率被下降了,因此要取一個平衡點;即便精通mysql的話,除了純技術面優化,還要根據業務面去優化sql語句,這樣才能達到最優效果;你敢說你的sql和索引已是最優了嗎?memcached
再說一下不一樣引擎的優化,myisam讀的效果好,寫的效率差,這和它數據存儲格式,索引的指針和鎖的策略有關的,它的數據是順序存儲的(innodb數據存儲方式是聚簇索引),他的索引btree上的節點是一個指向數據物理位置的指針,因此查找起來很快,(innodb索引節點存的則是數據的主鍵,因此須要根據主鍵二次查找);myisam鎖是表鎖,只有讀讀之間是併發的,寫寫之間和讀寫之間(讀和插入之間是能夠併發的,去設置concurrent_insert參數,按期執行表優化操做,更新操做就沒有辦法了)是串行的,因此寫起來慢,而且默認的寫優先級比讀優先級高,高到寫操做來了後,能夠立刻插入到讀操做前面去,若是批量寫,會致使讀請求餓死,因此要設置讀寫優先級或設置多少寫操做後執行讀操做的策略;myisam不要使用查詢時間太長的sql,若是策略使用不當,也會致使寫餓死,因此儘可能去拆分查詢效率低的sql,工具
innodb通常都是行鎖,這個通常指的是sql用到索引的時候,行鎖是加在索引上的,不是加在數據記錄上的,若是sql沒有用到索引,仍然會鎖定表,mysql的讀寫之間是能夠併發的,普通的select是不須要鎖的,當查詢的記錄遇到鎖時,用的是一致性的非鎖定快照讀,也就是根據數據庫隔離級別策略,會去讀被鎖定行的快照,其它更新或加鎖讀語句用的是當前讀,讀取原始行;由於普通讀與寫不衝突,因此innodb不會出現讀寫餓死的狀況,又由於在使用索引的時候用的是行鎖,鎖的粒度小,競爭相同鎖的狀況就少,就增長了併發處理,因此併發讀寫的效率仍是很優秀的,問題在於索引查詢後的根據主鍵的二次查找致使效率低;優化
ps:很奇怪,爲什innodb的索引葉子節點存的是主鍵而不是像mysism同樣存數據的物理地址指針嗎?若是存的是物理地址指針不就不須要二次查找了嗎,這也是我開始的疑惑,根據mysism和innodb數據存儲方式的差別去想,你就會明白了,我就不費口舌了!
因此innodb爲了不二次查找可使用索引覆蓋技術,沒法使用索引覆蓋的,再延伸一下就是基於索引覆蓋實現延遲關聯;不知道什麼是索引覆蓋的,建議你不管如何都要弄清楚它是怎麼回事!
盡你所能去優化你的sql吧!說它成本低,卻又是一項費時費力的活,須要在技術與業務都熟悉的狀況下,用心去優化才能作到最優,優化後的效果也是立竿見影的!