回覆列表
  • 1 # 使用者2774784654192103

    mysql bigint(20)中20指的是該欄位下能輸入的最大數字長度。

    括號裡的數字叫資料的寬度,不同的資料型別對寬度的處理也不一樣:

    1、整數型別,這裡顯示的寬度和資料型別的取值範圍是沒有任何關係的,顯示寬度只是指明Mysql最大可能顯示的數字個數,數值的位數小於指定的寬度時會由空格填充;如果插入了大於顯示寬度的值,只要該值不超過該型別的取值範圍,數值依然可以插入,而且能夠顯示出來。例如上面的udi,顯示的寬度是4,但是我向uid中插入100001,也是可以的,儲存和顯示的都會是100001;如果你不設定寬度,系統將新增預設的寬度tinyint(4),smallint(6),mediumint(9),int(11),bigint(20),這些預設的寬度是跟該型別的取值範圍長度相關。

    2、字串型別,字串型別這個寬度才真的用上了。不管是char還是varchar,寬度都定義了字串的最大長度;例如上面的 password varchar(20),如果你輸入了一個21個字元的密碼,那麼儲存和顯示的只會是前20個字元,你將丟失一個字元資訊,char同理。由於varchar是變長儲存的,所以實際開發中我們一般都把varchar的寬度設為最長255,反正你沒用完它也不會浪費空間。

    3、浮點和日期等資料型別對資料的寬度沒有要求,一般也不設定,預設是0。

  • 2 # 使用者1310383773116

    key是鍵的意思,key分為主鍵primary key,外來鍵FOREIGN KEY,以及一般鍵(即索引)。這句實際上建立了一個索引!

  • 3 # 過客看客過8848

    crud同時在一張表上併發進行,由於事務的隔離性,當表中資料很大時是肯定不行的。

    有人說使用讀寫分離,但對於寫來講,多個併發事務對同一張大表執行併發的事務性操作也會對效能造成極大影響。

    還有人說表分割槽,橫向分割槽只是減少了事務性操作的資料規模,把對一個數據集的操作分攤到多個數據集而已,對於千萬甚至上億數量級而言效果並不明顯。

    可以考慮使用事件溯源(Event Souring)+讀寫分離(CQRS)相結合的方法。事件溯源保證了只執行插入操作,而且插入的並不是資料本身,而是在事件表中插入新增資料的事件event,資料是以這個事件的屬性儲存的。對資料的修改和刪除也同樣是以事件形式插入事件表,這種只插入不修改或刪除保證了極其強大的時間效能。如果我們想獲取某一時刻的資料歷史值,則把這個資料從它的起始時刻到特定時刻之間的所有事件回放一遍,即可獲得當時的資料值。為了事件表本身的規模不至於太大,我們還可以定期生成它的快照,將在此之前的所有事件應用回放從而獲得每個資料的現場值並壓縮了事件表。

    除了事件溯源以外,我們還應該使用資料庫提供的資料複製功能(所有關係型資料庫都提供,例如mysql和mariadb的binlog)或使用第三方元件(例如阿里雲的canal)將事件實時複製到其他資料庫中,從而實現讀寫分離。這時也可以使用eventuate事件溯源框架,並結合kafka或rabbitmq作它的事件訊息匯流排。在用於讀的資料庫中我們一般使用物化檢視,也就是說,把接收到的事件直接應用在物化檢視上,終端使用者看到的是物化檢視中的統計分析資料。

  • 4 # 天天向上v天天上

    這個資料量,建索引,會影響插入更新的效能。遇到複雜多變的業務場景,那麼多的索引是很恐懼的。

    減少資料量,只有分庫分表,提高插入速度。

    但是分庫分表,會給正常的查詢帶來影響,也就是老的程式碼要重構了,還要考慮主鍵的生成。

    如果業務簡單,建議加索引,讀寫分離,加快取解決。

    如果業務複雜,還是直接上elasticsearch把。

  • 5 # 進擊的路路潘

    crud慢。。。insert慢你就分割槽,不影響業務分表分例項也行;update delete看你什麼模式了,如果是大資料量帶複雜條件的跟select一樣分析訪問路徑,總之先分析,別盲目的上方案,我見過更新資料花四十多分鐘,開發一群人討論分庫分表,後來調整了index變成四分鐘的,凡事都先分析一下,雖說工程師不是科學家,但是也別太無腦

  • 6 # 夕陽雨晴

    MySQL 資料庫某張表近千萬的資料,CRUD比較慢,如何最佳化?最常見的是執行緒池最佳化、索引最佳化、快取最佳化、讀寫分離、資料庫拆分等,上述4種最佳化可以從不同角度來最佳化我們的資料庫操作,其中的可操作性性要看團隊的技術能力和應用的維護能力,我就以自己遇到過的應用場景簡單談談自己的最佳化流程。

    換到新的團隊,遇到的第一個棘手問題就是資料庫不定時的出現“Cannot get a connection, pool error Timeout waiting for idle object”,經和DBA溝通,其反饋資料庫group(資料庫量級4kw+)中的查詢邏輯很多,qps達1w+,並且慢sql積壓,拖垮了資料庫。從慢sql和上述查詢異常著手,進行千萬級的資料庫最佳化。

    1. 執行緒池最佳化。線上的讀執行緒池16,寫執行緒池池16,考慮到資料查詢時獲取不到資料庫連線,將讀執行緒池調整為32,其最佳化效果不明顯,資料庫建立連線的異常仍然存在。

    2.索引最佳化。經和DBA分析相關的慢sql語句,發現其索引都是完備的,也就是說每個查詢都可以落到對應的索引邏輯,這點兒我們心裡是有數的,畢竟線上正常運行了2年多資料庫,當時建庫和查詢時肯定考慮到了索引的情況。也就是說,在這方面沒有最佳化的餘地。

    3.快取最佳化。經排查,線上的相關操作採用快取加速,快取時間1h或24h不等,考慮到資料庫瓶頸和更新資料刪快取的邏輯,將快取時間延長至7天。該最佳化邏輯上線後,資料庫異常有所減弱,但問題仍未解決。偶爾發現,客戶端偶爾會請求服務端不存在的資料,引發快取穿透。而針對該庫涉及到的可能存在快取穿透的邏輯,進行了一系列最佳化。最佳化之後,效果特別明顯,也就是在線上業務達到一定量級時,要特別注意快取穿透,這點在業務剛開始時很容易被忽略。

    4.讀寫分離。雖然透過快取穿透的最佳化處理,解決了資料庫連線異常的問題,但是讀寫分離仍然值得嘗試,讀寫分離是應對讀多寫少業務的一大利器,一主多從的讀寫分離模式被引入彈性資料庫體系,讓我們在特殊節點的業務保障更有信心。

    5.資料庫拆分,也就是分庫分表。業務發展到一定程度,分庫分表是最佳化的必經之路,也是我們團隊一項很重要的最佳化業務,但限於業務場景、分庫分表規則、多維度查詢、團隊研發資源等,目前正在規劃中。

    綜上所述,透過最佳化快取穿透和讀寫分離解決了我們線上業務的資料庫效能問題,可操作性強,風險相對降低。

  • 7 # DanielXU

    這樣的問題是不可能在不瞭解業務的情況下瞎分析,或者給方案的,如果可以的話,你就不會提這個問題了。簡而言之,離開業務談方案,都是耍流氓。 一症一方!

  • 8 # 程式設計師—成長之路

    資料千萬級別之多,佔用的儲存空間也比較大,可想而知它不會儲存在一塊連續的物理空間上,而是鏈式儲存在多個碎片的物理空間上。可能對於長字串的比較,就用更多的時間查詢與比較,這就導致用更多的時間。

    當MySQL單表記錄數過大時,資料庫的CRUD效能會明顯下降,一些常見的最佳化措施如下:

    1、限定資料的範圍: 務必禁止不帶任何限制資料範圍條件的查詢語句。比如:我們當用戶在查詢訂單歷史的時候,我們可以控制在一個月的範圍內。;

    2、讀/寫分離: 經典的資料庫拆分方案,主庫負責寫,從庫負責讀;

    3、快取: 使用MySQL的快取,另外對重量級、更新少的資料可以考慮使用應用級別的快取;

    4、透過分庫分表的方式進行最佳化,主要有垂直分表和水平分表

    垂直分表:

    根據資料庫裡面資料表的相關性進行拆分。 例如,使用者表中既有使用者的登入資訊又有使用者的基本資訊,可以將使用者表拆分成兩個單獨的表,甚至放到單獨的庫做分庫。

    簡單來說垂直拆分是指資料表列的拆分,把一張列比較多的表拆分為多張表。 如下圖所示,這樣來說大家應該就更容易理解了。

    垂直拆分的優點: 可以使得行資料變小,在查詢時減少讀取的Block數,減少I/O次數。此外,垂直分割槽可以簡化表的結構,易於維護。

    垂直拆分的缺點: 主鍵會出現冗餘,需要管理冗餘列,並會引起Join操作,可以透過在應用層進行Join來解決。此外,垂直分割槽會讓事務變得更加複雜;

    水平分表:

    保持資料表結構不變,透過某種策略儲存資料分片。這樣每一片資料分散到不同的表或者庫中,達到了分散式的目的。 水平拆分可以支撐非常大的資料量。

    水平拆分是指資料錶行的拆分,表的行數超過200萬行時,就會變慢,這時可以把一張表的資料拆成多張表來存放。舉個例子:我們可以將使用者資訊表拆分成多個使用者資訊表,這樣就可以避免單一表資料量過大對效能造成影響。

    水平拆分能夠 支援非常大的資料量儲存,應用端改造也少,但 分片事務難以解決 ,跨界點Join效能較差,邏輯複雜。

  • 9 # 博睿資料

    當MySQL單表記錄數過大時,增刪改查效能都會急劇下降。可以透過單表最佳化、限定資料的範圍、表分割槽、讀寫分離等方法進行最佳化。

    單表最佳化

    除非單表資料未來會一直不斷上漲,否則不要一開始就考慮拆分,拆分會帶來邏輯、部署、運維的各種複雜度,一般以整型值為主的表在千萬級以下,字串為主的表在五百萬以下是沒有太大問題的。而事實上很多時候MySQL單表的效能依然有不少最佳化空間,甚至能正常支撐千萬級以上的資料量。

    欄位

    (1)儘量使用TINYINT、SMALLINT、MEDIUM_INT作為整數型別而非INT,如果非負則加上UNSIGNED(2)VARCHAR的長度只分配真正需要的空間(3)使用列舉或整數代替字串型別(4)儘量使用TIMESTAMP而非DATETIME,(5)單表不要有太多欄位,建議在20個以內(6)避免使用NULL欄位,很難查詢最佳化且佔用額外索引空間,並且導致索引失效(7)用整型來存IP

    索引

    (1)索引並不是越多越好,要根據查詢有針對性的建立,考慮在WHERE和ORDER BY命令上涉及的列建立索引,可根據EXPLAIN來檢視是否用了索引還是全表掃描(2)儘量避免在WHERE子句中對欄位進行NULL值判斷,否則將導致引擎放棄使用索引而進行全表掃描(3)值分佈很稀少的欄位不適合建索引,例如"性別"這種只有兩三個值的欄位(4)字元欄位只建字首索引(5)字元欄位最好不要做主鍵(6)不用外來鍵和級聯更新,級聯更新是強阻塞操作,且對於資料更新不最佳化,容易導致更新風暴,外來鍵和級聯更新在應用程式中實現。(7)儘量不用UNIQUE,由程式保證約束(8)使用多列索引時主意順序和查詢條件保持一致,同時刪除不必要的單列索引

    SQL最佳化

    (1)可透過開啟慢查詢日誌來找出較慢的SQL(2)不對索引欄位進行運算,會導致索引失效:SELECT id WHERE age + 1 = 10,任何對列的操作都將導致表掃描,它包括資料庫教程函式、計算表示式等等,查詢時要儘可能將操作移至等號右邊(3)sql語句儘可能簡單:一條sql只能在一個cpu運算;大語句拆小語句,減少鎖時間;一條大sql可以堵死整個庫(4)不用SELECT *,查詢所有資料會增加I/O和網路傳輸負擔。(5)OR改寫成IN:OR的效率是n級別,IN的效率是log(n)級別,in的個數建議控制在200以內(6)不用函式和觸發器,在應用程式實現(7)避免%xxx式查詢(8)優先使用聯表查詢而不是巢狀子查詢。(9)使用同類型進行比較,比如用’123’和’123’比,123和123比(10)儘量避免在WHERE子句中使用!=或<>運算子,否則將引擎放棄使用索引而進行全表掃描(11)對於連續數值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5(12)列表資料不要拿全表,要使用LIMIT來分頁,每頁數量也不要太大

    引擎

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

    MyISAM

    MyISAM引擎是MySQL 5.1及之前版本的預設引擎,它的特點是:不支援行鎖,讀取時對需要讀到的所有表加鎖,寫入時則對錶加排它鎖不支援事務不支援外來鍵不支援崩潰後的安全恢復在表有讀取查詢的同時,支援往表中插入新紀錄支援BLOB和TEXT的前500個字元索引,支援全文索引支援延遲更新索引,極大提升寫入效能對於不會進行修改的表,支援壓縮表,極大減少磁碟空間佔用

    InnoDB

    InnoDB在MySQL 5.5後成為預設索引,它的特點是:支援行鎖,採用MVCC來支援高併發支援事務支援外來鍵支援崩潰後的安全恢復支援全文索引( innodb在mysql 5.6.4已經支援全文索引)

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

    系統調優引數

    可以使用下面幾個工具來做基準測試:(1)sysbench:一個模組化,跨平臺以及多執行緒的效能測試工具(2)iibench-mysql:基於 Java 的 MySQL/Percona/MariaDB 索引進行插入效能測試工具(3)tpcc-mysql:Percona開發的TPC-C測試工具

    具體的調優引數內容較多,具體可參考官方文件,這裡介紹一些比較重要的引數:(1)back_log:back_log值指出在MySQL暫時停止回答新請求之前的短時間內多少個請求可以被存在堆疊中。也就是說,如果MySql的連線資料達到max_connections時,新來的請求將會被存在堆疊中,以等待某一連線釋放資源,該堆疊的數量即back_log,如果等待連線的數量超過back_log,將不被授予連線資源。可以從預設的50升至500(2)wait_timeout:資料庫連線閒置時間,閒置連線會佔用記憶體資源。可以從預設的8小時減到半小時(3)max_user_connection: 最大連線數,預設為0無上限,最好設一個合理上限(4)thread_concurrency:併發執行緒數,設為CPU核數的兩倍(5)skip_name_resolve:禁止對外部連線進行DNS解析,消除DNS解析時間,但需要所有遠端主機用IP訪問(6)key_buffer_size:索引塊的快取大小,增加會提升索引處理速度,對MyISAM表效能影響最大。對於記憶體4G左右,可設為256M或384M,透過查詢(7)show status like ‘key_read%’,保證key_reads / key_read_requests在0.1%以下最好(8)innodb_buffer_pool_size:快取資料塊和索引塊,對InnoDB表效能影響最大。透過查詢show status like ‘Innodb_buffer_pool_read%’,保證 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests越高越好(9)innodb_additional_mem_pool_size:InnoDB儲存引擎用來存放資料字典資訊以及一些內部資料結構的記憶體空間大小,當資料庫物件非常多的時候,適當調整該引數的大小以確保所有資料都能存放在記憶體中提高訪問效率,當過小的時候,MySQL會記錄Warning資訊到資料庫的錯誤日誌中,這時就需要該調整這個引數大小(10)innodb_log_buffer_size:InnoDB儲存引擎的事務日誌所使用的緩衝區,一般來說不建議超過32MB(11)query_cache_size:快取MySQL中的ResultSet,也就是一條SQL語句執行的結果集,所以僅僅只能針對select語句。當某個表的資料有任何任何變化,都會導致所有引用了該表的select語句在Query Cache中的快取資料失效。所以,當我們的資料變化非常頻繁的情況下,使用Query Cache可能會得不償失。根據命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))進行調整,一般不建議太大,256MB可能已經差不多了,大型的配置型靜態資料可適當調大.可以透過命令show status like "Qcache_%"檢視目前系統Query catch使用大小(12)read_buffer_size:MySql讀入緩衝區大小。對錶進行順序掃描的請求將分配一個讀入緩衝區,MySql會為它分配一段記憶體緩衝區。如果對錶的順序掃描請求非常頻繁,可以透過增加該變數值以及記憶體緩衝區大小提高其效能(13)sort_buffer_size:MySql執行排序使用的緩衝大小。如果想要增加ORDER BY的速度,首先看是否可以讓MySQL使用索引而不是額外的排序階段。如果不能,可以嘗試增加sort_buffer_size變數的大小(14)read_rnd_buffer_size:MySql的隨機讀緩衝區大小。當按任意順序讀取行時(例如,按照排序順序),將分配一個隨機讀快取區。進行排序查詢時,MySql會首先掃描一遍該緩衝,以避免磁碟搜尋,提高查詢速度,如果需要排序大量資料,可適當調高該值。但MySql會為每個客戶連線發放該緩衝空間,所以應儘量適當設定該值,以避免記憶體開銷過大。(15)record_buffer:每個進行一個順序掃描的執行緒為其掃描的每張表分配這個大小的一個緩衝區。如果你做很多順序掃描,可能想要增加該值(16)thread_cache_size:儲存當前沒有與連線關聯但是準備為後面新的連線服務的執行緒,可以快速響應連線的執行緒請求而無需建立新的(17)table_cache:類似於thread_cache_size,但用來快取表文件,對InnoDB效果不大,主要用於MyISAM

    升級硬體

    Scale up,這個不多說了,根據MySQL是CPU密集型還是I/O密集型,透過提升CPU和記憶體、使用SSD,都能顯著提升MySQL效能

    讀寫分離

    讀寫分離也是目前常用的最佳化,從庫讀主庫寫,一般不要採用雙主或多主引入很多複雜性,儘量採用文中的其他方案來提高效能。同時目前很多拆分的解決方案同時也兼顧考慮了讀寫分離。

    快取

    快取可以發生在這些層次:(1)MySQL內部:在系統調優引數介紹了相關設定(2)資料訪問層:比如MyBatis針對SQL語句做快取,而Hibernate可以精確到單個記錄,這裡快取的物件主要是持久化物件Persistence Object(3)應用服務層:這裡可以透過程式設計手段對快取做到更精準的控制和更多的實現策略,這裡快取的物件是資料傳輸物件Data Transfer Object(4)Web層:針對web頁面做快取(5)瀏覽器客戶端:使用者端的快取

    可以根據實際情況在一個層次或多個層次結合加入快取。這裡重點介紹下服務層的快取實現,目前主要有兩種方式:(1)直寫式(Write Through):在資料寫入資料庫後,同時更新快取,維持資料庫與快取的一致性。這也是當前大多數應用快取框架如Spring Cache的工作方式。這種實現非常簡單,同步好,但效率一般。(2)回寫式(Write Back):當有資料要寫入資料庫時,只會更新快取,然後非同步批次的將快取資料同步到資料庫上。這種實現比較複雜,需要較多的應用邏輯,同時可能會產生資料庫與快取的不同步,但效率非常高。

    表分割槽

    MySQL在5.1版引入的分割槽是一種簡單的水平拆分,使用者需要在建表的時候加上分割槽引數,對應用是透明的無需修改程式碼。

    對使用者來說,分割槽表是一個獨立的邏輯表,但是底層由多個物理子表組成,實現分割槽的程式碼實際上是透過對一組底層表的物件封裝,但對SQL層來說是一個完全封裝底層的黑盒子。MySQL實現分割槽的方式也意味著索引也是按照分割槽的子表定義,沒有全域性索引。

    使用者的SQL語句是需要針對分割槽表做最佳化,SQL條件中要帶上分割槽條件的列,從而使查詢定位到少量的分割槽上,否則就會掃描全部分割槽,可以透過EXPLAIN PARTITIONS來檢視某條SQL語句會落在那些分割槽上,從而進行SQL最佳化,如下圖5條記錄落在兩個分割槽上:

    分割槽的好處

    (1)可以讓單表儲存更多的資料(2)分割槽表的資料更容易維護,可以透過清楚整個分割槽批次刪除大量資料,也可以增加新的分割槽來支援新插入的資料。另外,還可以對一個獨立分割槽進行最佳化、檢查、修復等操作(3)部分查詢能夠從查詢條件確定只落在少數分割槽上,速度會很快(4)分割槽表的資料還可以分佈在不同的物理裝置上,從而搞笑利用多個硬體裝置(5)可以使用分割槽表賴避免某些特殊瓶頸,例如InnoDB單個索引的互斥訪問、ext3檔案系統的inode鎖競爭(6)可以備份和恢復單個分割槽

    分割槽的限制和缺點

    (1)一個表最多隻能有1024個分割槽(2)如果分割槽欄位中有主鍵或者唯一索引的列,那麼所有主鍵列和唯一索引列都必須包含進來(3)分割槽表無法使用外來鍵約束(4)NULL值會使分割槽過濾無效(5)所有分割槽必須使用相同的儲存引擎

    分割槽的型別

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

    分割槽適合的場景有

    最適合分割槽的場景是資料的時間序列性比較強,可以按時間來分割槽,如下所示:

    如果資料有明顯的熱點,而且除了這部分資料,其他資料很少被訪問到,那麼可以將熱點資料單獨放在一個分割槽,讓這個分割槽的資料能夠有機會都快取在記憶體中,查詢時只訪問一個很小的分割槽表,能夠有效使用索引和快取。

    垂直拆分

    垂直分庫是根據資料庫裡面的資料表的相關性進行拆分,比如:一個數據庫裡面既存在使用者資料,又存在訂單資料,那麼垂直拆分可以把使用者資料放到使用者庫、把訂單資料放到訂單庫。垂直分表是對資料表進行垂直拆分的一種方式,常見的是把一個多欄位的大表按常用欄位非常用欄位進行拆分,每個表裡面的資料記錄數一般情況下是相同的,只是欄位不一樣,使用主鍵關聯

    比如原始的使用者表如下

    垂直拆分後如下

    垂直拆分的優點

    (1)可以使得行資料變小,一個數據塊(Block)就能存放更多的資料,在查詢時就會減少I/O次數(每次查詢時讀取的Block 就少)(2)可以達到最大化利用Cache的目的,具體在垂直拆分的時候可以將不常變的欄位放一起,將經常改變的放一起(3)資料維護簡單

    垂直拆分的缺點

    (1)主鍵出現冗餘,需要管理冗餘列(2)會引起表連線JOIN操作(增加CPU開銷)可以透過在業務伺服器上進行join來減少資料庫壓力(3)依然存在單表資料量過大的問題(需要水平拆分)(4)事務處理複雜

    水平拆分(分片)

    水平拆分是透過某種策略將資料分片來儲存,分為庫內分表分庫兩部分,每片資料會分散到不同的MySQL表或庫,達到分散式的效果,能夠支援非常大的資料量。前面的表分割槽本質上也是一種特殊的庫內分表。

    庫內分表,僅僅是單純的解決了單一表資料過大的問題,由於沒有把表的資料分佈到不同的機器上,因此對於減輕MySQL伺服器的壓力來說,並沒有太大的作用,大家還是競爭同一個物理機上的IO、CPU、網路。可以透過分庫來解決這一問題。

    前面垂直拆分的使用者表如果進行水平拆分,結果如下

    實際情況中往往會是垂直拆分和水平拆分的結合,即將Users_A_M和Users_N_Z再拆成Users和UserExtras,這樣一共形成四張表。

    水平拆分的優點

    (1)不存在單庫大資料和高併發的效能瓶頸(2)應用端改造較少(3)提高了系統的穩定性和負載能力

    水平拆分的缺點

    (1)分片事務一致性難以解決(2)跨節點Join效能差,邏輯複雜(3)資料多次擴充套件難度跟維護量極大

    分片原則

    (1)能不分就不分,優先進行單表最佳化(2)分片數量儘量少,分片儘量均勻分佈在多個數據結點上,因為一個查詢SQL跨分片越多,則總體效能越差,雖然要好於所有資料在一個分片的結果,只在必要的時候進行擴容,增加分片數量(3)分片規則需要慎重選擇做好提前規劃,分片規則的選擇,需要考慮資料的增長模式,資料的訪問模式,分片關聯性問題,以及分片擴容問題,最近的分片策略為範圍分片,列舉分片,一致性Hash分片,這幾種分片都有利於擴容(4)儘量不要在一個事務中的SQL跨越多個分片,分散式事務一直是個不好處理的問題(5)查詢條件儘量最佳化,儘量避免Select * 的方式,大量資料結果集下,會消耗大量頻寬和CPU資源,查詢儘量避免返回大量結果集,並且儘量為頻繁使用的查詢語句建立索引。(6)透過資料冗餘和表分割槽賴降低跨庫Join的可能

    這裡特別強調一下分片規則的選擇問題,如果某個表的資料有明顯的時間特徵,比如訂單、交易記錄等,則他們通常比較合適用時間範圍分片,因為具有時效性的資料,我們往往關注其近期的資料,查詢條件中往往帶有時間欄位進行過濾,比較好的方案是,當前活躍的資料,採用跨度比較短的時間段進行分片,而歷史性的資料,則採用比較長的跨度儲存。

    總體上來說,分片的選擇是取決於最頻繁的查詢SQL的條件,因為不帶任何Where語句的查詢SQL,會遍歷所有的分片,效能相對最差,因此這種SQL越多,對系統的影響越大,所以我們要儘量避免這種SQL的產生。

    資料庫分片的兩種常見方案

    由於水平拆分牽涉的邏輯比較複雜,當前也有了不少比較成熟的解決方案。這些方案分為兩大類:客戶端架構和代理架構。

    客戶端架構

    透過修改資料訪問層,如JDBC、Data Source、MyBatis,透過配置來管理多個數據源,直連資料庫,並在模組內完成資料的分片整合,一般以Jar包的方式呈現

    這是一個客戶端架構的例子:

    可以看到分片的實現是和應用伺服器在一起的,透過修改Spring JDBC層來實現。客戶端架構的優點是:(1)應用直連資料庫,降低外圍系統依賴所帶來的宕機風險;(2)整合成本低,無需額外運維的元件客戶端架構的缺點是:(1)限於只能在資料庫訪問層上做文章,擴充套件性一般,對於比較複雜的系統可能會力不從心;(2)將分片邏輯的壓力放在應用伺服器上,造成額外風險。

    代理架構

    透過獨立的中介軟體來統一管理所有資料來源和資料分片整合,後端資料庫叢集對前端應用程式透明,需要獨立部署和運維代理元件

    這是一個代理架構的例子:

    代理元件為了分流和防止單點,一般以叢集形式存在,同時可能需要Zookeeper之類的服務元件來管理

    代理架構的優點是:(1)能夠處理非常複雜的需求,不受資料庫訪問層原來實現的限制,擴充套件性強;(2)對於應用伺服器透明且沒有增加任何額外負載。缺點是:(1)需部署和運維獨立的代理中介軟體,成本高;(2)應用需經過代理來連線資料庫,網路上多了一跳,效能有損失且有額外風險。

    各種方案比較

    如此多的方案,如何進行選擇?可以按以下思路來考慮:(1)確定是使用代理架構還是客戶端架構。中小型規模或是比較簡單的場景傾向於選擇客戶端架構,複雜場景或大規模系統傾向選擇代理架構(2)具體功能是否滿足,比如需要跨節點ORDER BY,那麼支援該功能的優先考慮(3)不考慮一年內沒有更新的產品,說明開發停滯,甚至無人維護和技術支援(4)最好按大公司->社群->小公司->個人這樣的出品方順序來選擇(5)選擇口碑較好的,比如github星數、使用者數量質量和使用者反饋(6)開源的優先,往往專案有特殊需求可能需要改動原始碼

    按照上述思路,推薦以下選擇:客戶端架構:ShardingJDBC代理架構:MyCat或者Atlas

    相容MySQL且可水平擴充套件的資料庫

    目前也有一些開源資料庫相容MySQL協議,如:TiDBCubrid

    但其工業品質和MySQL尚有差距,且需要較大的運維投入,如果想將原始的MySQL遷移到可水平擴充套件的新資料庫中,可以考慮一些雲資料庫:阿里雲PetaData阿里雲OceanBase騰訊雲DCDB

    NoSQL

    在MySQL上做Sharding是一種戴著鐐銬的跳舞,事實上很多大表本身對MySQL這種RDBMS的需求並不大,並不要求ACID,可以考慮將這些表遷移到NoSQL,徹底解決水平擴充套件問題,例如:日誌類、監控類、統計類資料非結構化或弱結構化資料對事務要求不強,且無太多關聯操作的資料

  • 中秋節和大豐收的關聯?
  • 用超級拇指盆控養的多肉是什麼樣子的?