MySQL 對於千萬級的大表要怎麼優化? - MySQL - 知乎【方法論】html
MySQL大表優化方案【一些優化的細節操做】mysql
MySQL大表優化方案【一些優化的細節操做】redis
分佈式數據庫下子查詢和join等複雜sql如何實現?【分佈式數據庫相關】sql
本篇內容只是大綱,將來對本文中提到的細節還需一一實踐並總結。mongodb
哪一種類型的業務不須要關係型數據庫,NOSQL就能夠?數據庫
基於hadoop、spark構建OLAP系統,採用redis來作緩存,怎麼搞?segmentfault
MYSQL數據庫 通常都是按照這個步驟去演化的,成本也是由低到高;緩存
第一優化,sql和索引;服務器
第二加緩存,memcached,redis;架構
第三以上都作了後,仍是慢,就作主從複製或主主複製,讀寫分離,能夠在應用層作,效率高,也能夠用三方工具,第三方工具推薦360的atlas,其它的要麼效率不高,要麼沒人維護;
|-- Goto: MySQL主從複製(Master-Slave)實踐【不錯,結尾引用也不錯】
第四若是以上都作了仍是慢,mysql自帶分區表,先試試這個,對你的應用是透明的,無需更改代碼,可是sql語句是須要針對分區表作優化的,sql條件中要帶上分區條件的列,從而使查詢定位到少許的分區上,不然就會掃描所有分區,另外分區表還有一些坑,在這裏就很少說了;
第五若是以上都作了,那就先作垂直拆分,其實就是根據你模塊的耦合度,將一個大的系統分爲多個小的系統,也就是分佈式系統;
第六纔是水平切分,針對數據量大的表,這一步最麻煩,最能考驗技術水平,要選擇一個合理的sharding key,爲了有好的查詢效率,表結構也要改動,作必定的冗餘,應用也要改,sql中儘可能帶sharding key,將數據定位到限定的表上去查,而不是掃描所有的表;
|-- Goto: 關於數據庫的水平切分和垂直切分的一些概念
有人也許要說第一步優化sql和索引這還用說嗎?的確,你們都知道,可是不少狀況下,這一步作的並不到位,甚至有的只作了根據sql去建索引,根本沒對sql優化(中槍了沒?),除了最簡單的增刪改查外,想實現一個查詢,能夠寫出不少種查詢語句,不一樣的語句,根據你選擇的引擎、表中數據的分佈狀況、索引狀況、數據庫優化策略、查詢中的鎖策略等因素,最終查詢的效率相差很大;
優化要從總體去考慮,有時你優化一條語句後,其它查詢反而效率被下降了,因此要取一個平衡點;即便精通mysql的話,除了純技術面優化,還要根據業務面去優化sql語句,這樣才能達到最優效果;你敢說你的sql和索引已是最優了嗎?
MYISAM 和 INNODB 是Mysql數據庫提供的兩種存儲引擎。二者的優劣可謂是各有千秋。INNODB會支持一些關係數據庫的高級功能,如事務功能和行級鎖,MYISAM不支持。MYISAM的性能更優,佔用的存儲空間少。因此,選擇何種存儲引擎,視具體應用而定。
再說一下不一樣引擎的優化,myisam讀的效果好,寫的效率差,這和它數據存儲格式,索引的指針和鎖的策略有關的,它的數據是順序存儲的(innodb數據存儲方式是聚簇索引),他的索引btree上的節點是一個指向數據物理位置的指針,因此查找起來很快,(innodb索引節點存的則是數據的主鍵,因此須要根據主鍵二次查找);myisam鎖是表鎖,只有讀讀之間是併發的,寫寫之間和讀寫之間(讀和插入之間是能夠併發的,去設置concurrent_insert參數,按期執行表優化操做,更新操做就沒有辦法了)是串行的,因此寫起來慢,而且默認的寫優先級比讀優先級高,高到寫操做來了後,能夠立刻插入到讀操做前面去,若是批量寫,會致使讀請求餓死,因此要設置讀寫優先級或設置多少寫操做後執行讀操做的策略;myisam不要使用查詢時間太長的sql,若是策略使用不當,也會致使寫餓死,因此儘可能去拆分查詢效率低的sql。
innodb通常都是行鎖,這個通常指的是sql用到索引的時候,行鎖是加在索引上的,不是加在數據記錄上的,若是sql沒有用到索引,仍然會鎖定表,mysql的讀寫之間是能夠併發的,普通的select是不須要鎖的,當查詢的記錄遇到鎖時,用的是一致性的非鎖定快照讀,也就是根據數據庫隔離級別策略,會去讀被鎖定行的快照,其它更新或加鎖讀語句用的是當前讀,讀取原始行;由於普通讀與寫不衝突,因此innodb不會出現讀寫餓死的狀況,又由於在使用索引的時候用的是行鎖,鎖的粒度小,競爭相同鎖的狀況就少,就增長了併發處理,因此併發讀寫的效率仍是很優秀的,問題在於索引查詢後的根據主鍵的二次查找致使效率低;
ps:很奇怪,爲什innodb的索引葉子節點存的是主鍵而不是像mysism同樣存數據的物理地址指針嗎?若是存的是物理地址指針不就不須要二次查找了嗎,這也是我開始的疑惑,根據mysism和innodb數據存儲方式的差別去想,你就會明白了,我就不費口舌了!因此innodb爲了不二次查找可使用索引覆蓋技術,沒法使用索引覆蓋的,再延伸一下就是基於索引覆蓋實現延遲關聯;不知道什麼是索引覆蓋的,建議你不管如何都要弄清楚它是怎麼回事!盡你所能去優化你的sql吧!說它成本低,卻又是一項費時費力的活,須要在技術與業務都熟悉的狀況下,用心去優化才能作到最優,優化後的效果也是立竿見影的!
1 | 數據的容量 | 1-3年內會大概多少條數據,每條數據大概多少字節 |
2 | 數據項 | 是否有大字段,那些字段的值是否常常被更新 |
3 | 數據查詢SQL條件 | 哪些數據項的列名稱常常出如今WHERE、GROUP BY、ORDER BY子句中等 |
4 | 數據更新類SQL條件 | 有多少列常常出現UPDATE或DELETE 的WHERE子句中 |
5 | SQL量的統計比 | 如:SELECT:UPDATE+DELETE:INSERT=多少? |
6 | 執行量數量級 | 預計大表及相關聯的SQL,天天總的執行量在何數量級? |
7 | 表中的數據 | 更新爲主的業務 仍是 查詢爲主的業務 |
8 | 什麼架構 | 打算採用什麼數據庫物理服務器,以及數據庫服務器架構? |
9 | 併發如何 | 採用怎麼的處理併發的策略 |
10 | 存儲引擎 | 存儲引擎選擇InnoDB仍是MyISAM? |
至於優化如果指建立好的表,不能變更表結構的話,那建議InnoDB引擎,多利用點內存,減輕磁盤IO負載,由於IO每每是數據庫服務器的瓶頸。
另外對優化索引結構去解決性能問題的話,建議優先考慮修改類SQL語句,使他們更快些,不得已只靠索引組織結構的方式,固然此話前提是,
索引已經建立的很是好,如果讀爲主,能夠考慮打開query_cache, 以及調整一些參數值:sort_buffer_size, read_buffer_size, read_rnd_buffer_size, join_buffer_size
下面是一些相關測試和對比
(1) 首先看engine,在大數據量狀況下,在沒有作分區的狀況下
mysiam比innodb在只讀的狀況下,效率要高13%左右
(2) 在作了partition以後,你能夠去讀一下mysql的官方文檔,其實對於partition,專門是對myisam作的優化;對於innodb,全部的數據是存在ibdata裏面的,因此即便你能夠看到schema變了,其實沒有本質的變化
在分區出於同一個physical disk下面的狀況下,提高大概只有1%
在分區在不一樣的physical disk下,我分到了三個不一樣的disks下,提高大概在3%,其實所謂的吞吐量,由不少因素決定的,好比你的explain parition時候能夠看到,record在那一個分區,若是每一個分區都有,其實本質上沒有解決讀的問題,這樣只會提高寫的效率。
另一個問題在於,分區,你怎麼分,若是一張表,有三個column都是常常被用於作查詢條件的,實際上是一件很悲慘的事情,由於你沒有辦法對全部的sql作針對性的分區,若是你只是如mysql官方文檔上說的,只對時間作一個分區,並且你也只用時間查詢的話,恭喜你
(3) 表主要用來讀仍是寫,其實這個問題是不充分的,應該這樣問,你在寫入的時候,同時併發的查詢多麼?個人問題還比較簡單,由於mongodb的shredding支持不能,在crush以後,仍是回到mysql,因此在一般狀況下,9am-9pm,寫入的狀況不少,這個時候我會作一個view,view是基於最近被插入或者常常被查詢的,經過作view來分離讀取,就是說寫是在table上的,讀在進行邏輯判斷前是在view上操做的
(4) 作一些archive table,好比先對這些大表作不少已有的統計分析,而後經過已有的分析+增量來解決
(5) 若是你用mysiam,還有一個問題你要注意,若是你的.configure的時候,加了一個max index length參數的時候,當你的record數大於制定長度的時候,這個index會被disable