MySQL 對於千萬級的大表要怎麼優化? MySQL 對於千萬級的大表要怎麼優化?

MySQL 對於千萬級的大表要怎麼優化?我寫了6000字的深度解讀

 

千萬級大表如何優化,這是一個很有技術含量的問題,通常我們的直覺思維都會跳轉到拆分或者數據分區,在此我想做一些補充和梳理,想和大家做一些這方面的經驗總結,也歡迎大家提出建議。

 

從一開始腦海裏開始也是火光四現,到不斷的自我批評,後來也參考了一些團隊的經驗,我整理了下面的大綱內容。

 

 

既然要喫透這個問題,我們勢必要回到本源,我把這個問題分爲三部分:

“千萬級”,“大表”,“優化”,

也分別對應我們在圖中標識的

“數據量”,“對象”和“目標”。

 

我來逐步展開說明一下,從而給出一系列的解決方案。

1.數據量:千萬級

千萬級其實只是一個感官的數字,就是我們印象中的數據量大。 這裏我們需要把這個概念細化,因爲隨着業務和時間的變化,數據量也會有變化,我們應該是帶着一種動態思維來審視這個指標,從而對於不同的場景我們應該有不同的處理策略。

1) 數據量爲千萬級,可能達到億級或者更高

通常是一些數據流水,日誌記錄的業務,裏面的數據隨着時間的增長會逐步增多,超過千萬門檻是很容易的一件事情。

2) 數據量爲千萬級,是一個相對穩定的數據量

如果數據量相對穩定,通常是在一些偏向於狀態的數據,比如有1000萬用戶,那麼這些用戶的信息在表中都有相應的一行數據記錄,隨着業務的增長,這個量級相對是比較穩定的。

 

3) 數據量爲千萬級,不應該有這麼多的數據

這種情況是我們被動發現的居多,通常發現的時候已經晚了,比如你看到一個配置表,數據量上千萬;或者說一些表裏的數據已經存儲了很久,99%的數據都屬於過期數據或者垃圾數據。

 

數據量是一個整體的認識,我們需要對數據做更近一層的理解,這就可以引出第二個部分的內容。

2.對象:數據表

數據操作的過程就好比數據庫中存在着多條管道,這些管道中都流淌着要處理的數據,這些數據的用處和歸屬是不一樣的。

一般根據業務類型把數據分爲三種:

(1)流水型數據

流水型數據是無狀態的,多筆業務之間沒有關聯,每次業務過來的時候都會產生新的單據,比如交易流水、支付流水,只要能插入新單據就能完成業務,特點是後面的數據不依賴前面的數據,所有的數據按時間流水進入數據庫。

(2)狀態型數據

狀態型數據是有狀態的,多筆業務之間依賴於有狀態的數據,而且要保證該數據的準確性,比如充值時必須要拿到原來的餘額,才能支付成功。

(3)配置型數據

此類型數據數據量較小,而且結構簡單,一般爲靜態數據,變化頻率很低。

至此,我們可以對整體的背景有一個認識了,如果要做優化,其實要面對的是這樣的3*3的矩陣,如果要考慮表的讀寫比例(讀多寫少,讀少寫多...),那麼就會是3*3*4=24種,顯然做窮舉是不顯示的,而且也完全沒有必要,可以針對不同的數據存儲特性和業務特點來指定不同的業務策略。

對此我們採取抓住重點的方式,把常見的一些優化思路梳理出來,尤其是裏面的核心思想,也是我們整個優化設計的一把尺子,而難度決定了我們做這件事情的動力和風險。

而對於優化方案,我想採用面向業務的維度來進行闡述。

 

3.目標:優化

在這個階段,我們要說優化的方案了,總結的有點多,相對來說是比較全了。

整體分爲五個部分:

 

 

其實我們通常所說的分庫分表等方案只是其中的一小部分,如果展開之後就比較豐富了。

 

 

其實不難理解,我們要支撐的表數據量是千萬級別,相對來說是比較大了,DBA要維護的表肯定不止一張,如何能夠更好的管理,同時在業務發展中能夠支撐擴展,同時保證性能,這是擺在我們面前的幾座大山。

我們分別來說一下這五類改進方案:

優化設計方案1.規範設計

在此我們先提到的是規範設計,而不是其他高大上的設計方案。

黑格爾說:秩序是自由的第一條件。在分工協作的工作場景中尤其重要,否則團隊之間互相牽制太多,問題多多。

規範設計我想提到如下的幾個規範,其實只是屬於開發規範的一部分內容,可以作爲參考。

 

 

規範的本質不是解決問題,而是有效杜絕一些潛在問題,對於千萬級大表要遵守的規範,我梳理了如下的一些細則,基本可以涵蓋我們常見的一些設計和使用問題,比如表的字段設計不管三七二十一,都是varchar(500),其實是很不規範的一種實現方式,我們來展開說一下這幾個規範。

 

1)配置規範

(1)MySQL數據庫默認使用InnoDB存儲引擎。

(2)保證字符集設置統一,MySQL數據庫相關係統、數據庫、表的字符集使都用UTF8,應用程序連接、展示等可以設置字符集的地方也都統一設置爲UTF8字符集。

注:UTF8格式是存儲不了表情類數據,需要使用UTF8MB4,可在MySQL字符集裏面設置。在8.0中已經默認爲UTF8MB4,可以根據公司的業務情況進行統一或者定製化設置。

(3)MySQL數據庫的事務隔離級別默認爲RR(Repeatable-Read),建議初始化時統一設置爲RC(Read-Committed),對於OLTP業務更適合。

(4)數據庫中的表要合理規劃,控制單表數據量,對於MySQL數據庫來說,建議單表記錄數控制在2000W以內。

(5)MySQL實例下,數據庫、表數量儘可能少;數據庫一般不超過50個,每個數據庫下,數據表數量一般不超過500個(包括分區表)。

 

2)建表規範

(1)InnoDB禁止使用外鍵約束,可以通過程序層面保證。

(2)存儲精確浮點數必須使用DECIMAL替代FLOAT和DOUBLE。

(3)整型定義中無需定義顯示寬度,比如:使用INT,而不是INT(4)。

(4)不建議使用ENUM類型,可使用TINYINT來代替。

(5)儘可能不使用TEXT、BLOB類型,如果必須使用,建議將過大字段或是不常用的描述型較大字段拆分到其他表中;另外,禁止用數據庫存儲圖片或文件。

(6)存儲年時使用YEAR(4),不使用YEAR(2)。

(7)建議字段定義爲NOT NULL。

(8)建議DBA提供SQL審覈工具,建表規範性需要通過審覈工具審覈後

 

3)命名規範

(1)庫、表、字段全部採用小寫。

(2)庫名、表名、字段名、索引名稱均使用小寫字母,並以“_”分割。

(3)庫名、表名、字段名建議不超過12個字符。(庫名、表名、字段名支持最多64個字符,但爲了統一規範、易於辨識以及減少傳輸量,統一不超過12字符)

(4)庫名、表名、字段名見名知意,不需要添加註釋。

對於對象命名規範的一個簡要總結如下表4-1所示,供參考。

4)索引規範

(1)索引建議命名規則:idx_col1_col2[_colN]、uniq_col1_col2[_colN](如果字段過長建議採用縮寫)。

(2)索引中的字段數建議不超過5個。

(3)單張表的索引個數控制在5個以內。

(4)InnoDB表一般都建議有主鍵列,尤其在高可用集羣方案中是作爲必須項的。

(5)建立複合索引時,優先將選擇性高的字段放在前面。

(6)UPDATE、DELETE語句需要根據WHERE條件添加索引。

(7)不建議使用%前綴模糊查詢,例如LIKE “%weibo”,無法用到索引,會導致全表掃描。

(8)合理利用覆蓋索引,例如:

(9)SELECT email,uid FROM user_email WHERE uid=xx,如果uid不是主鍵,可以創建覆蓋索引idx_uid_email(uid,email)來提高查詢效率。

(10)避免在索引字段上使用函數,否則會導致查詢時索引失效。

(11)確認索引是否需要變更時要聯繫DBA。

 

5)應用規範

(1)避免使用存儲過程、觸發器、自定義函數等,容易將業務邏輯和DB耦合在一起,後期做分佈式方案時會成爲瓶頸。

(2)考慮使用UNION ALL,減少使用UNION,因爲UNION ALL不去重,而少了排序操作,速度相對比UNION要快,如果沒有去重的需求,優先使用UNION ALL。

(3)考慮使用limit N,少用limit M,N,特別是大表或M比較大的時候。

(4)減少或避免排序,如:group by語句中如果不需要排序,可以增加order by null。

(5)統計表中記錄數時使用COUNT(*),而不是COUNT(primary_key)和COUNT(1);InnoDB表避免使用COUNT(*)操作,計數統計實時要求較強可以使用Memcache或者Redis,非實時統計可以使用單獨統計表,定時更新。

(6)做字段變更操作(modify column/change column)的時候必須加上原有的註釋屬性,否則修改後,註釋會丟失。

(7)使用prepared statement可以提高性能並且避免SQL注入。

(8)SQL語句中IN包含的值不應過多。

(9)UPDATE、DELETE語句一定要有明確的WHERE條件。

(10)WHERE條件中的字段值需要符合該字段的數據類型,避免MySQL進行隱式類型轉化。

(11)SELECT、INSERT語句必須顯式的指明字段名稱,禁止使用SELECT * 或是INSERT INTO table_name values()。

(12)INSERT語句使用batch提交(INSERT INTO table_name VALUES(),(),()……),values的個數不應過多。

 

優化設計方案2:業務層優化

業務層優化應該是收益最高的優化方式了,而且對於業務層完全可見,主要有業務拆分,數據拆分和兩類常見的優化場景(讀多寫少,讀少寫多)

 

 

1)業務拆分

ü 將混合業務拆分爲獨立業務

ü 將狀態和歷史數據分離

業務拆分其實是把一個混合的業務剝離成爲更加清晰的獨立業務,這樣業務1,業務2。。。獨立的業務使得業務總量依舊很大,但是每個部分都是相對獨立的,可靠性依然有保證。

對於狀態和歷史數據分離,我可以舉一個例子來說明。

例如:我們有一張表Account,假設用戶餘額爲100。

 

 

我們需要在發生數據變更後,能夠追溯數據變更的歷史信息,如果對賬戶更新狀態數據,增加100的餘額,這樣餘額爲200。

這個過程可能對應一條update語句,一條insert語句。

對此我們可以改造爲兩個不同的數據源,account和account_hist

在account_hist中就會是兩條insert記錄,如下:

 

 

而在account中則是一條update語句,如下:

 

 

這也是一種很基礎的冷熱分離,可以大大減少維護的複雜度,提高業務響應效率。

2)數據拆分

2.1 按照日期拆分,這種使用方式比較普遍,尤其是按照日期維度的拆分,其實在程序層面的改動很小,但是擴展性方面的收益很大。

  • 數據按照日期維度拆分,如test_20191021
  • 數據按照周月爲維度拆分,如test_201910
  • 數據按照季度,年維度拆分,如test_2019

2.2 採用分區模式,分區模式也是常見的使用方式,採用hash,range等方式會多一些,在MySQL中我是不大建議使用分區表的使用方式,因爲隨着存儲容量的增長,數據雖然做了垂直拆分,但是歸根結底,數據其實難以實現水平擴展,在MySQL中是有更好的擴展方式。

2.3 讀多寫少優化場景

採用緩存,採用Redis技術,將讀請求打在緩存層面,這樣可以大大降低MySQL層面的熱點數據查詢壓力。

2.4 讀少寫多優化場景,可以採用三步走:

1) 採用異步提交模式,異步對於應用層來說最直觀的就是性能的提升,產生最少的同步等待。

2) 使用隊列技術,大量的寫請求可以通過隊列的方式來進行擴展,實現批量的數據寫入。

3) 降低寫入頻率,這個比較難理解,我舉個例子

對於業務數據,比如積分類,相比於金額來說業務優先級略低的場景,如果數據的更新過於頻繁,可以適度調整數據更新的範圍(比如從原來的每分鐘調整爲10分鐘)來減少更新的頻率。

例如:更新狀態數據,積分爲200,如下圖所示

 

 

可以改造爲,如下圖所示。

 

 

如果業務數據在短時間內更新過於頻繁,比如1分鐘更新100次,積分從100到10000,則可以根據時間頻率批量提交。

例如:更新狀態數據,積分爲100,如下圖所示。

 

 

無需生成100個事務(200條SQL語句)可以改造爲2條SQL語句,如下圖所示。

 

 

對於業務指標,比如更新頻率細節信息,可以根據具體業務場景來討論決定。

 

優化設計方案3:架構層優化

架構層優化其實就是我們認爲的那種技術含量很高的工作,我們需要根據業務場景在架構層面引入一些新的花樣來。

 

 

 

3.1.系統水平擴展場景

3.1.1採用中間件技術,可以實現數據路由,水平擴展,常見的中間件有MyCAT,ShardingSphere,ProxySQL等

 

 

3.1.2 採用讀寫分離技術,這是針對讀需求的擴展,更側重於狀態表,在允許一定延遲的情況下,可以採用多副本的模式實現讀需求的水平擴展,也可以採用中間件來實現,如MyCAT,ProxySQL,MaxScale,MySQL Router等

 

 

3.1.3 採用負載均衡技術,常見的有LVS技術或者基於域名服務的Consul技術等

 

3.2.兼顧OLTP+OLAP的業務場景,可以採用NewSQL,優先兼容MySQL協議的HTAP技術棧,如TiDB

3.3.離線統計的業務場景,有幾類方案可供選擇。

3.3.1 採用NoSQL體系,主要有兩類,一類是適合兼容MySQL協議的數據倉庫體系,常見的有Infobright或者ColumnStore,另外一類是基於列式存儲,屬於異構方向,如HBase技術

3.3.2 採用數倉體系,基於MPP架構,如使用Greenplum統計,如T+1統計

 

優化設計方案4:數據庫優化

 

數據庫優化,其實可打的牌也不少,但是相對來說空間沒有那麼大了,我們來逐個說一下。

 

 

 

4.1 事務優化

根據業務場景選擇事務模型,是否是強事務依賴

對於事務降維策略,我們來舉出幾個小例子來。

4.1.1 降維策略1:存儲過程調用轉換爲透明的SQL調用

對於新業務而言,使用存儲過程顯然不是一個好主意,MySQL的存儲過程和其他商業數據庫相比,功能和性能都有待驗證,而且在目前輕量化的業務處理中,存儲過程的處理方式太“重”了。

有些應用架構看起來是按照分佈式部署的,但在數據庫層的調用方式是基於存儲過程,因爲存儲過程封裝了大量的邏輯,難以調試,而且移植性不高,這樣業務邏輯和性能壓力都在數據庫層面了,使得數據庫層很容易成爲瓶頸,而且難以實現真正的分佈式。

所以有一個明確的改進方向就是對於存儲過程的改造,把它改造爲SQL調用的方式,可以極大地提高業務的處理效率,在數據庫的接口調用上足夠簡單而且清晰可控。

 

4.1.2 降維策略2:DDL操作轉換爲DML操作

有些業務經常會有一種緊急需求,總是需要給一個表添加字段,搞得DBA和業務同學都挺累,可以想象一個表有上百個字段,而且基本都是name1,name2……name100,這種設計本身就是有問題的,更不用考慮性能了。究其原因,是因爲業務的需求動態變化,比如一個遊戲裝備有20個屬性,可能過了一個月之後就增加到了40個屬性,這樣一來,所有的裝備都有40個屬性,不管用沒用到,而且這種方式也存在諸多的冗餘。

我們在設計規範裏面也提到了一些設計的基本要素,在這些基礎上需要補充的是,保持有限的字段,如果要實現這些功能的擴展,其實完全可以通過配置化的方式來實現,比如把一些動態添加的字段轉換爲一些配置信息。配置信息可以通過DML的方式進行修改和補充,對於數據入口也可以更加動態、易擴展。

4.1.3 降維策略3:Delete操作轉換爲高效操作

有些業務需要定期來清理一些週期性數據,比如表裏的數據只保留一個月,那麼超出時間範圍的數據就要清理掉了,而如果表的量級比較大的情況下,這種Delete操作的代價實在太高,我們可以有兩類解決方案來把Delete操作轉換爲更爲高效的方式。

第一種是根據業務建立週期表,比如按照月表、周表、日表等維度來設計,這樣數據的清理就是一個相對可控而且高效的方式了。

第二種方案是使用MySQL rename的操作方式,比如一張2千萬的大表要清理99%的數據,那麼需要保留的1%的數據我們可以很快根據條件過濾補錄,實現“移形換位”。

 

4.2 SQL優化

其實相對來說需要的極簡的設計,很多點都在規範設計裏面了,如果遵守規範,八九不離十的問題都會杜絕掉,在此補充幾點:

4.2.1 SQL語句簡化,簡化是SQL優化的一大利器,因爲簡單,所以優越。

4.2.2 儘可能避免或者杜絕多表複雜關聯,大表關聯是大表處理的噩夢,一旦打開了這個口子,越來越多的需求需要關聯,性能優化就沒有回頭路了,更何況大表關聯是MySQL的弱項,儘管Hash Join才推出,不要像掌握了絕對大殺器一樣,在商業數據庫中早就存在,問題照樣層出不窮。

4.2.3 SQL中儘可能避免反連接,避免半連接,這是優化器做得薄弱的一方面,什麼是反連接,半連接?其實比較好理解,舉個例子,not in ,not exists就是反連接,in,exists就是半連接,在千萬級大表中出現這種問題,性能是幾個數量級的差異。

 

4.3 索引優化

應該是大表優化中需要把握的一個度。

4.3.1 首先必須有主鍵,規範設計中第一條就是,此處不接收反駁。

4.3.2 其次,SQL查詢基於索引或者唯一性索引,使得查詢模型儘可能簡單。

4.3.3 最後,儘可能杜絕範圍數據的查詢,範圍掃描在千萬級大表情況下還是儘可能減少。

優化設計方案4:管理優化

這部分應該是在所有的解決方案中最容易被忽視的部分了,我放在最後,在此也向運維同事致敬,總是爲很多認爲本應該正常的問題盡職盡責(背鍋)。

 

 

千萬級大表的數據清理一般來說是比較耗時的,在此建議在設計中需要完善冷熱數據分離的策略,可能聽起來比較拗口,我來舉一個例子,把大表的Drop 操作轉換爲可逆的DDL操作。

Drop操作是默認提交的,而且是不可逆的,在數據庫操作中都是跑路的代名詞,MySQL層面目前沒有相應的Drop操作恢復功能,除非通過備份來恢復,但是我們可以考慮將Drop操作轉換爲一種可逆的DDL操作。

MySQL中默認每個表有一個對應的ibd文件,其實可以把Drop操作轉換爲一個rename操作,即把文件從testdb遷移到testdb_arch下面;從權限上來說,testdb_arch是業務不可見的,rename操作可以平滑的實現這個刪除功能,如果在一定時間後確認可以清理,則數據清理對於已有的業務流程是不可見的,如下圖所示。

 

 

 

此外,還有兩個額外建議,一個是對於大表變更,儘可能考慮低峯時段的在線變更,比如使用pt-osc工具或者是維護時段的變更,就不再贅述了。

 

 

最後總結一下,其實就是一句話:

千萬級大表的優化是根據業務場景,以成本爲代價進行優化的,絕對不是孤立的一個層面的優化。

 

個人新書 《MySQL DBA工作筆記》

個人公衆號:jianrong-notes


 

MySQL 對於千萬級的大表要怎麼優化?

作者:互聯網編程
鏈接:https://www.zhihu.com/question/19719997/answer/549041957
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

問題概述

使用阿里雲rds for MySQL數據庫(就是MySQL5.6版本),有個用戶上網記錄表6個月的數據量近2000萬,保留最近一年的數據量達到4000萬,查詢速度極慢,日常卡死。嚴重影響業務。

問題前提:老系統,當時設計系統的人大概是大學沒畢業,表設計和sql語句寫的不僅僅是垃圾,簡直無法直視。原開發人員都已離職,到我來維護,這就是傳說中的維護不了就跑路,然後我就是掉坑的那個!!!

我嘗試解決該問題,so,有個這個日誌。

方案概述

  • 方案一:優化現有mysql數據庫。優點:不影響現有業務,源程序不需要修改代碼,成本最低。缺點:有優化瓶頸,數據量過億就玩完了。
  • 方案二:升級數據庫類型,換一種100%兼容mysql的數據庫。優點:不影響現有業務,源程序不需要修改代碼,你幾乎不需要做任何操作就能提升數據庫性能,缺點:多花錢
  • 方案三:一步到位,大數據解決方案,更換newsql/nosql數據庫。優點:沒有數據容量瓶頸,缺點:需要修改源程序代碼,影響業務,總成本最高。

 

以上三種方案,按順序使用即可,數據量在億級別一下的沒必要換nosql,開發成本太高。三種方案我都試了一遍,而且都形成了落地解決方案。該過程心中慰問跑路的那幾個開發者一萬遍 :)

方案一詳細說明:優化現有mysql數據庫

跟阿里雲數據庫大佬電話溝通 and Google解決方案 and 問羣裏大佬,總結如下(都是精華):

  • 1.數據庫設計和表創建時就要考慮性能
  • 2.sql的編寫需要注意優化
  • 3.分區
  • 4.分表
  • 5.分庫

1.數據庫設計和表創建時就要考慮性能

mysql數據庫本身高度靈活,造成性能不足,嚴重依賴開發人員能力。也就是說開發人員能力高,則mysql性能高。這也是很多關係型數據庫的通病,所以公司的dba通常工資巨高。

設計表時要注意:

  • 表字段避免null值出現,null值很難查詢優化且佔用額外的索引空間,推薦默認數字0代替null。
  • 儘量使用INT而非BIGINT,如果非負則加上UNSIGNED(這樣數值容量會擴大一倍),當然能使用TINYINT、SMALLINT、MEDIUM_INT更好。
  • 使用枚舉或整數代替字符串類型
  • 儘量使用TIMESTAMP而非DATETIME
  • 單表不要有太多字段,建議在20以內
  • 用整型來存IP

索引

  • 索引並不是越多越好,要根據查詢有針對性的創建,考慮在WHERE和ORDER BY命令上涉及的列建立索引,可根據EXPLAIN來查看是否用了索引還是全表掃描
  • 應儘量避免在WHERE子句中對字段進行NULL值判斷,否則將導致引擎放棄使用索引而進行全表掃描
  • 值分佈很稀少的字段不適合建索引,例如"性別"這種只有兩三個值的字段
  • 字符字段只建前綴索引
  • 字符字段最好不要做主鍵
  • 不用外鍵,由程序保證約束
  • 儘量不用UNIQUE,由程序保證約束
  • 使用多列索引時主意順序和查詢條件保持一致,同時刪除不必要的單列索引

簡言之就是使用合適的數據類型,選擇合適的索引

1.選擇合適的數據類型

  • (1)使用可存下數據的最小的數據類型,整型 < date,time < char,varchar < blob
  • (2)使用簡單的數據類型,整型比字符處理開銷更小,因爲字符串的比較更復雜。如,int類型存儲時間類型,bigint類型轉ip函數
  • (3)使用合理的字段屬性長度,固定長度的表會更快。使用enum、char而不是varchar
  • (4)儘可能使用not null定義字段
  • (5)儘量少用text,非用不可最好分表

2.選擇合適的索引列

  • (1)查詢頻繁的列,在where,group by,order by,on從句中出現的列
  • (2)where條件中<,<=,=,>,>=,between,in,以及like 字符串+通配符(%)出現的列
  • (3)長度小的列,索引字段越小越好,因爲數據庫的存儲單位是頁,一頁中能存下的數據越多越好
  • (4)離散度大(不同的值多)的列,放在聯合索引前面。查看離散度,通過統計不同的列值來實現,count越大,離散程度越高:
原開發人員已經跑路,該表早已建立,我無法修改,故:該措辭無法執行,放棄!

2.sql的編寫需要注意優化

  • 使用limit對查詢結果的記錄進行限定
  • 避免select *,將需要查找的字段列出來
  • 使用連接(join)來代替子查詢
  • 拆分大的delete或insert語句
  • 可通過開啓慢查詢日誌來找出較慢的SQL
  • 不做列運算:SELECT id WHERE age + 1 = 10,任何對列的操作都將導致表掃描,它包括數據庫教程函數、計算表達式等等,查詢時要儘可能將操作移至等號右邊
  • sql語句儘可能簡單:一條sql只能在一個cpu運算;大語句拆小語句,減少鎖時間;一條大sql可以堵死整個庫
  • OR改寫成IN:OR的效率是n級別,IN的效率是log(n)級別,in的個數建議控制在200以內
  • 不用函數和觸發器,在應用程序實現
  • 避免%xxx式查詢
  • 少用JOIN
  • 使用同類型進行比較,比如用'123'和'123'比,123和123比
  • 儘量避免在WHERE子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描
  • 對於連續數值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5
  • 列表數據不要拿全表,要使用LIMIT來分頁,每頁數量也不要太大
原開發人員已經跑路,程序已經完成上線,我無法修改sql,故:該措辭無法執行,放棄!

引擎

引擎

目前廣泛使用的是MyISAM和InnoDB兩種引擎:

1. MyISAM

MyISAM引擎是MySQL 5.1及之前版本的默認引擎,它的特點是:

  • 不支持行鎖,讀取時對需要讀到的所有表加鎖,寫入時則對錶加排它鎖
  • 不支持事務
  • 不支持外鍵
  • 不支持崩潰後的安全恢復
  • 在表有讀取查詢的同時,支持往表中插入新紀錄
  • 支持BLOB和TEXT的前500個字符索引,支持全文索引
  • 支持延遲更新索引,極大提升寫入性能
  • 對於不會進行修改的表,支持壓縮表,極大減少磁盤空間佔用

2. InnoDB

InnoDB在MySQL 5.5後成爲默認索引,它的特點是:

  • 支持行鎖,採用MVCC來支持高併發
  • 支持事務
  • 支持外鍵
  • 支持崩潰後的安全恢復
  • 不支持全文索引

總體來講,MyISAM適合SELECT密集型的表,而InnoDB適合INSERT和UPDATE密集型的表

MyISAM速度可能超快,佔用存儲空間也小,但是程序要求事務支持,故InnoDB是必須的,故該方案無法執行,放棄!

3.分區

MySQL在5.1版引入的分區是一種簡單的水平拆分,用戶需要在建表的時候加上分區參數,對應用是透明的無需修改代碼

對用戶來說,分區表是一個獨立的邏輯表,但是底層由多個物理子表組成,實現分區的代碼實際上是通過對一組底層表的對象封裝,但對SQL層來說是一個完全封裝底層的黑盒子。MySQL實現分區的方式也意味着索引也是按照分區的子表定義,沒有全局索引

用戶的SQL語句是需要針對分區表做優化,SQL條件中要帶上分區條件的列,從而使查詢定位到少量的分區上,否則就會掃描全部分區,可以通過EXPLAIN PARTITIONS來查看某條SQL語句會落在那些分區上,從而進行SQL優化,我測試,查詢時不帶分區條件的列,也會提高速度,故該措施值得一試。

分區的好處是:

  • 可以讓單表存儲更多的數據
  • 分區表的數據更容易維護,可以通過清楚整個分區批量刪除大量數據,也可以增加新的分區來支持新插入的數據。另外,還可以對一個獨立分區進行優化、檢查、修復等操作
  • 部分查詢能夠從查詢條件確定只落在少數分區上,速度會很快
  • 分區表的數據還可以分佈在不同的物理設備上,從而搞笑利用多個硬件設備
  • 可以使用分區表賴避免某些特殊瓶頸,例如InnoDB單個索引的互斥訪問、ext3文件系統的inode鎖競爭
  • 可以備份和恢復單個分區

分區的限制和缺點:

  • 一個表最多隻能有1024個分區
  • 如果分區字段中有主鍵或者唯一索引的列,那麼所有主鍵列和唯一索引列都必須包含進來
  • 分區表無法使用外鍵約束
  • NULL值會使分區過濾無效
  • 所有分區必須使用相同的存儲引擎

分區的類型:

  • RANGE分區:基於屬於一個給定連續區間的列值,把多行分配給分區
  • LIST分區:類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇
  • HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數可以包含MySQL中有效的、產生非負整數值的任何表達式
  • KEY分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL服務器提供其自身的哈希函數。必須有一列或多列包含整數值

具體關於mysql分區的概念請自行google或查詢官方文檔,我這裏只是拋磚引玉了。

我首先根據月份把上網記錄表RANGE分區了12份,查詢效率提高6倍左右,效果不明顯,故:換id爲HASH分區,分了64個分區,查詢速度提升顯著。問題解決!
結果如下:PARTITION BY HASH (id)PARTITIONS 64

select count(*) from readroom_website; --11901336行記錄

/* 受影響行數: 0 已找到記錄: 1 警告: 0 持續時間 1 查詢: 5.734 sec. */

select * from readroom_website where month(accesstime) =11 limit 10;

/* 受影響行數: 0 已找到記錄: 10 警告: 0 持續時間 1 查詢: 0.719 sec. */

4.分表

分表就是把一張大表,按照如上過程都優化了,還是查詢卡死,那就把這個表分成多張表,把一次查詢分成多次查詢,然後把結果組合返回給用戶。

分表分爲垂直拆分和水平拆分,通常以某個字段做拆分項。比如以id字段拆分爲100張表: 表名爲 tableName_id%100

但:分表需要修改源程序代碼,會給開發帶來大量工作,極大的增加了開發成本,故:只適合在開發初期就考慮到了大量數據存在,做好了分表處理,不適合應用上線了再做修改,成本太高!!!而且選擇這個方案,都不如選擇我提供的第二第三個方案的成本低!故不建議採用。

5.分庫

把一個數據庫分成多個,建議做個讀寫分離就行了,真正的做分庫也會帶來大量的開發成本,得不償失!不推薦使用。

方案二詳細說明:升級數據庫,換一個100%兼容mysql的數據庫

mysql性能不行,那就換個。爲保證源程序代碼不修改,保證現有業務平穩遷移,故需要換一個100%兼容mysql的數據庫。

1. 開源選擇

開源數據庫會帶來大量的運維成本且其工業品質和MySQL尚有差距,有很多坑要踩,如果你公司要求必須自建數據庫,那麼選擇該類型產品。

2. 雲數據選擇

  • 阿里雲POLARDB

雲數據庫POLARDB_高吞吐在線事務處理_關係型雲數據庫_價格_購買 - 阿里雲

官方介紹語:POLARDB 是阿里雲自研的下一代關係型分佈式雲原生數據庫,100%兼容MySQL,存儲容量最高可達 100T,性能最高提升至 MySQL 的 6 倍。POLARDB 既融合了商業數據庫穩定、可靠、高性能的特徵,又具有開源數據庫簡單、可擴展、持續迭代的優勢,而成本只需商用數據庫的 1/10。

我開通測試了一下,支持免費mysql的數據遷移,無操作成本,性能提升在10倍左右,價格跟rds相差不多,是個很好的備選解決方案!

  • 阿里雲OcenanBase

淘寶使用的,扛得住雙十一,性能卓著,但是在公測中,我無法嘗試,但值得期待

  • 阿里雲HybridDB for MySQL (原PetaData)

雲數據庫HybridDB for MySQL_產品詳情_阿里雲

官方介紹:雲數據庫HybridDB for MySQL (原名PetaData)是同時支持海量數據在線事務(OLTP)和在線分析(OLAP)的HTAP(Hybrid Transaction/Analytical Processing)關係型數據庫。

我也測試了一下,是一個olap和oltp兼容的解決方案,但是價格太高,每小時高達10塊錢,用來做存儲太浪費了,適合存儲和分析一起用的業務。

  • 騰訊雲DCDB

分佈式數據庫 - 騰訊雲

官方介紹:DCDB又名TDSQL,一種兼容MySQL協議和語法,支持自動水平拆分的高性能分佈式數據庫——即業務顯示爲完整的邏輯表,數據卻均勻的拆分到多個分片中;每個分片默認採用主備架構,提供災備、恢復、監控、不停機擴容等全套解決方案,適用於TB或PB級的海量數據場景。

騰訊的我不喜歡用,不多說。原因是出了問題找不到人,線上問題無法解決頭疼!但是他價格便宜,適合超小公司,玩玩。

方案三詳細說明:去掉mysql,換大數據引擎處理數據

數據量過億了,沒得選了,只能上大數據了。

1. 開源解決方案

hadoop家族。hbase/hive懟上就是了。但是有很高的運維成本,一般公司是玩不起的,沒十萬投入是不會有很好的產出的!

2.雲解決方案

這個就比較多了,也是一種未來趨勢,大數據由專業的公司提供專業的服務,小公司或個人購買服務,大數據就像水/電等公共設施一樣,存在於社會的方方面面。

國內做的最好的當屬阿里雲。

我選擇了阿里雲的MaxCompute配合DataWorks,使用超級舒服,按量付費,成本極低。

MaxCompute可以理解爲開源的Hive,提供sql/mapreduce/ai算法/python腳本/shell腳本等方式操作數據,數據以表格的形式展現,以分佈式方式存儲,採用定時任務和批處理的方式處理數據。DataWorks提供了一種工作流的方式管理你的數據處理任務和調度監控。

當然你也可以選擇阿里雲hbase等其他產品,我這裏主要是離線處理,故選擇MaxCompute,基本都是圖形界面操作,大概寫了300行sql,費用不超過100塊錢就解決了數據處理問題。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章