1. 程式人生 > >Mysql大資料量問題與解決

Mysql大資料量問題與解決

今日格言:瞭解了為什麼,問題就解決了一半。

Mysql 單表適合的最大資料量是多少?

我們說 Mysql 單表適合儲存的最大資料量,自然不是說能夠儲存的最大資料量,如果是說能夠儲存的最大量,那麼,如果你使用自增 ID,最大就可以儲存 2^32 或 2^64 條記錄了,這是按自增 ID 的資料型別 int 或 bigint 來計算的;如果你不使用自增 id,且沒有 id 最大值的限制,如使用足夠長度的隨機字串,那麼能夠限制單表最大資料量的就只剩磁碟空間了。顯然我們不是在討論這個問題。

影響 Mysql 單表的最優最大數量的一個重要因素其實是索引。

我們知道 Mysql 的主要儲存引擎 InnoDB 採用 B+樹結構索引。(至於為什麼 Mysql 選擇 b+樹而不是其他資料結構來組織索引,不是本文討論的話題,之後的文章會講到。)那麼 B+樹索引是如何影響 Mysql 單表資料量的呢?

B+樹

一棵 B+樹如下所示:

Mysql 的 B+樹索引儲存在磁碟上,Mysql 每次讀取磁碟 Page 的大小是 16KB,為了保證每次查詢的效率,需要保證每次查詢訪問磁碟的次數,一般設計為 2-3 次磁碟訪問,再多效能將嚴重不足。Mysql B+樹索引的每個節點需要儲存一個指標(8Byte)和一個鍵值(8Byte)。因此計算16KB/(8B+8B)=1K 16KB 可以儲存 1K 個節點,3 次磁碟訪問(即 B+樹 3 的深度)可以儲存 1K _ 1K _ 1K 即 10 億資料。

如果查詢依賴非主鍵索引,那麼還涉及二級索引。這樣資料量將更小。

拆分

分而治之——沒有什麼問題不能通過拆分一次來解決,不行就拆多次。

Mysql 單表儲存的資料量有限。一個解決大資料量儲存的辦法就是分庫分表。說白了就是一個數據庫一張表放不下那麼多資料,那就分多個數據庫多張表儲存。

拆分可分為垂直拆分和水平拆分。

垂直拆分是按照不同的表(或者 Schema)來切分到不同的資料庫(主機)之上,水平拆分則是根據表中的資料的邏輯關係,將同一個表中的資料按照某種條件拆分到多臺資料庫(主機)上面或多張相同 Schema 的不同表中。

垂直拆分的最大特點就是規則簡單,實施也更為方便,尤其適合各業務之間的耦合度非常低,相互影響很小,業務邏輯非常清晰的系統。在這種系統中,可以很容易做到將不同業務模組所使用的表分拆到不同的資料庫中。根據不同的表來進行拆分,對應用程式的影響也更小,拆分規則也會比較簡單清晰。

水平拆分與垂直切分相比,相對來說稍微複雜一些。因為要將同一個表中的不同資料拆分到不同的資料庫中,對於應用程式來說,拆分規則本身就較根據表名來拆分更為複雜,後期的資料維護也會更為複雜一些。

垂直拆分最直接的就是按領域拆分服務,隔離領域資料庫。如此每個庫所承擔的資料壓力就減少了。

水平拆分就是將同一個 Schema 的資料拆分到不同的庫或不同的表中,這樣每個表的資料量也將減小,查詢效率將更高效。水平拆分就涉及到表的分片規則問題。

幾種典型的分片規則包括:

  • 按照使用者 ID 求模,將資料分散到不同的資料庫,具有相同資料使用者的資料都被分散到一個庫中。
  • 按照日期,將不同月甚至日的資料分散到不同的庫中。
  • 按照某個特定的欄位求摸,或者根據特定範圍段分散到不同的庫中。

實現

門面模式——沒有什麼問題不能通過新增一箇中間層來解決。

垂直拆分的一個方案就是在應用層使用多個數據源,按業務訪問不同的資料來源。另外更好方案其實就是微服務化。按不同的業務領域來拆分微服務,明確領域邊界,隔離領域資料庫。這樣將對資料的存取內聚到獨立的服務之中,對外提供統一的介面。在需要同時依賴多個服務時,我們可以通過新增門面應用來組合底層服務的資料,以提供更符合上層業務需求的介面,這些服務往往更接近真實的業務。而底層的服務則是更加內聚的資源服務。

代理模式——沒有什麼問題不能通過新增一箇中間層來解決。

對於水平拆分應該儘量遮蔽拆分帶來的資料訪問困惱,為了讓上層業務無需關心下層資料組織方式。水平拆分往往通過新增一個代理層來做這些事情,代理層對上提供虛擬表,這些虛擬表就像我們在單庫上設計的單表一樣;代理層對下解析和拆分執行 sql,然後按相應規則在不同的庫和表執行相應的 sql 請求,再合併資料,並將合併後的結果返回給上層呼叫者。

一般代理方式分為如下兩種:

  • 程序內代理

    程序內代理即將代理層嵌入到業務服務內部,攔截 sql 請求並做相應的處理。這樣的好處是簡單,但是侵入性大,且不夠靈活。

  • 程序外代理

    程序外代理即將代理獨立成服務,代理真實業務服務和資料庫之間的請求。這樣是比較複雜的,需要高可用的代理服務架構。但是這樣對業務的侵入性低,且易於升級擴充套件。

問題

分散式事務問題

什麼是分散式事務?本地事務的定義就是一系列相關的資料庫操作完成後要滿足 ACID 四大特性,而分散式事務就是將同一程序的操作放到不同的微服務程序中,即不同微服務應用程序的資料庫操作滿足事務要求,或者對不同資料庫的一系列操作需滿足事務要求。

這裡就有兩個問題需要解決。一個是因為應用的分散式造成的,一個是因為資料庫本身的分散式造成的。資料庫本身的分散式事務問題一般由資料庫自身解決,大多數分散式資料庫都可以做到一定的資料一致性保證,如 HBase 保證的強一致性,Cassandra 保證的最終一致性。

應用資料的一致性事務方案我們也可以參考分散式資料庫的實現原理來實現。業界也有很多分散式事務的解決思路,如:

  • XA 方案
  • TCC 方案
  • 本地訊息表
  • 可靠訊息最終一致性方案
  • 最大努力通知方案

多表 Join 問題

通過分析 Join sql,將 sql 拆分成獨立的查詢請求,然後分別執行,並將結果合併計算返回給呼叫者。這個地方會涉及到很多執行優化的問題。

資料統計問題

當資料被分片到不同的資料庫或不同的表中時,要對資料做一些全域性的或涉及大量資料的統計時便會遇到一些問題。如求 Max,Min,Sum 等聚合問題。如果統計的資料有一定的業務規則,如只會按使用者維度去統計,如統計某個使用者的訂單量,那麼對訂單表的分片,其實可以採用按使用者 id 來分片,如此就可以解決這類統計問題。但是這種方案不通用。很多分片代理服務都需要將 sql 分片到不同的節點上去執行,然後再合併結果返回。

ID 問題

使用分庫分表之後,就無法使用 Mysql 的表自增作為 id,因為不同庫和表的自增將出現衝突的 id。解決這個問題就需要引入分散式 id 生成技術(將在以後的文章中講到)。

推薦系列:

列式儲存
時間序列資料庫(TSDB)初識與選擇
十分鐘瞭解 Apache Druid
Apache Druid 底層儲存設計
Apache Druid 的叢集設計與工作流程

想了解更多資料儲存相關知識,請關注我的公眾號。

相關推薦

Mysql料量問題解決

今日格言:瞭解了為什麼,問題就解決了一半。 Mysql 單表適合的最大資料量是多少? 我們說 Mysql 單表適合儲存的最大資料量,自然不是說能夠儲存的最大資料量,如果是說能夠儲存的最大量,那麼,如果你使用自增 ID,最大就可以儲存 2^32 或 2^64 條記錄了,這是按自增 ID 的資料型別 int

java mysql料量批量插入流式讀取分析

總結下這周幫助客戶解決報表生成操作的mysql 驅動的使用上的一些問題,與解決方案。由於生成報表邏輯要從資料庫讀取大量資料並在記憶體中加工處理後在 生成大量的彙總資料然後寫入到資料庫。基本流程是 讀取->處理->寫入。 1 讀取操作開始遇到的問題是當sql查詢資料量比較大時候基本讀不出來。開始

mysql料量下優化

1 優化sql和索引2 增加快取如:redis3 主從複製或主主複製,讀寫分離4 利用mysql自帶分割槽表5 先做垂直拆分,將一個大系統分為多個小系統,也就是分散式6 水平切分,要選擇一個合理的sharding key,為了有好的查詢效率,表結構也要改動,做一定的冗餘,應用也要改,sql中儘量帶shardi

料量 UI互動時的處理 總結心得

【以下均在主執行緒中操作時】1、UI直接操作,資料量較大時,直接使用UI會非常慢2、資料驅動操作,資料量較大時,資料與UI的互動效率相比“1”提升明顯總結:但以上這兩種操作  都會“較長時間”佔用主執行緒,導致UI假死現象【解決辦法,以下兩點並用】1、非同步,使用子執行緒處理耗時業務邏輯,避免因主執

MySQL料量分頁查詢方法及其優化 MySQL料量分頁查詢方法及其優化

MySQL大資料量分頁查詢方法及其優化   ---方法1: 直接使用資料庫提供的SQL語句---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適應場景: 適用於資料量較少的情況(元組百/千級) --

keras料量訓練解決方法

當資料量很大時無法將資料全部讀入記憶體運算,報錯,可以改用批處理解決問題。 一.pandas讀資料時可以設定成批量讀入 二.使用keras中的train_on_batch方法 示例程式碼: reader = pd.read_table('tmp.sv', sep=',', chunk

MySQL料量分頁查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句 ---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適

測試實驗 1.   直接用limit start, count分頁語句, 也是我程式中用的方法: select * from product limit start, count 當起始頁較小時,查詢沒有效能問題,我們分別看下從10, 100, 1000, 10000開始分頁的執行時間(每頁取20條), 如

MySQL 料量表優化方案

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

mysql 料量分頁優化

假設有一個千萬量級的表,取1到10條資料; select * from table limit 0,10; select * from table limit 1000,10; 這兩條語句查詢時間應該在毫秒級完成; select * from table limit

MySQL料量分頁查詢方法及其優化

方法1: 直接使用資料庫提供的SQL語句 語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N 適應場景: 適用於資料量較少的情況(元組百/千級) 原因/缺點: 全表掃描,速度會很慢 且 有的資料庫結果集返回不穩定(如某次返回

通過索引,極大提高MySQL料量下的查詢效率

我在這裡測試了兩個表的左連線查詢,SQL語句是:select a.blog_id,a.blog_title,a.blog_thumb,a.blog_click,a.blog_addtime,a.blog_show,b.blog_category_name from `thin

mysql 料量時 limit查詢優化

一般,我們在做分頁時,用的是語句如下:select * from table LIMIT 5,10; #返回第6-15行資料但是,如果資料量很大,比如>1000萬,則利用以上的查詢會非常慢,可以利用以下語句進行優化:Select * From table Where I

MySql 料量快速插入和語句優化

INSERT語句的速度 插入一個記錄需要的時間由下列因素組成,其中的數字表示大約比例:連線:(3) 傳送查詢給伺服器:(2) 分析查詢:(2) 插入記錄:(1x記錄大小) 插入索引:(1x索引) 關閉:(1) 這不考慮開啟表的初始開銷,每個併發執行的查詢開啟。

MySQL料量快速分頁實現

以下分享一點我的經驗 一般剛開始學SQL語句的時候,會這樣寫 程式碼如下: SELECT * FROM table ORDER BY id LIMIT 1000, 10; 但在資料達到百萬級的時候,這樣寫會慢死 程式碼如下: SELECT * FROM tabl

.NET 料量併發解決方案

大併發大資料量請求一般會分為幾種情況:大量的使用者同時對系統的不同功能頁面進行查詢、更新操作大量的使用者同時對系統的同一個頁面,同一個表的大資料量進行查詢操作大量的使用者同時對系統的同一個頁面,同一個表進行更新操作第一類情況 :大量的使用者同時對系統的不同功能頁面進行查詢、更

Mysql料量儲存及訪問的設計討論-設計

轉載請註明來源:Mysql大資料量儲存及訪問的設計討論    一、引言   隨著網際網路應用的廣泛普及,海量資料的儲存和訪問成為了系統設計的瓶頸問題。對於一個大型的網際網路應用,每天幾十億的PV無疑對資料庫造成了相當高的負載。對於系統的穩定性和擴充套件性造成了極大的問題。通過

MySQL料量分頁SQL語句優化

分頁程式原理很簡單,這裡就不多說了,本篇文章主要說的是在資料表記錄量比較大的情況下,如何將分頁SQL做到更優化,讓MySQL執行的更快的方法。 一般的情況下,我們的分頁SQL語句是這樣的:

提高MYSQL料量查詢的速度

1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t wher

利用MySQL資料庫如何解決料量儲存問題?

一、概述 分表是個目前算是比較炒的比較流行的概念,特別是在大負載的情況下,分表是一個良好分散資料庫壓力的好方法。 首先要了解為什麼要分表,分表的好處是什麼。我們先來大概瞭解以下一個資料庫執行SQL的過程: 接收到SQL --> 放入SQL執行佇列 --> 使用分析器分解SQL -->

四種快排兩種歸併和堆和插入排序 料量執行時間比較

#include"iostream" #include"iomanip" #include"stdlib.h" #include"time.h" #include"string" /*由於我電腦記憶體有限所以資料量最大能執行在20w*/ //三路快排適用於有大量重複值的資