Ⅰ mysql用分庫分表後還需要寫復雜的SQL語句嗎
肯定需要啊,分庫分表是把大表拆分成小表,但是表之間的關聯變多了。
Ⅱ mysql分庫分表後如何統計
資料庫分庫分表是緩解資料庫伺服器壓力和增加並發量的途徑之一,但是隨著分庫分表之後,也不可避免的帶來了一些問題,很顯而易見的問題就是如何解決分庫後的查詢統計。分庫之後沒有SQL可以用了,簡單的過濾後再合並還可以做,但分組都會很麻煩,必須把分庫分組匯總結集再分組匯總。這對很多java應用程序員來講是個挑戰。但是,數據量太大大,不分庫也不行,進退兩難。
這時候,採用集算器來做後一步的匯總計算就很容易,比如剛才說的分組匯總問題,寫出來只要這么幾行:
這里實現分組的代碼還考慮了讓分庫並行執行SQL。
利用集算器實現分庫匯總里包含幾個典型例子來說明分庫匯總的用法,跨庫數據表的運算 是有關分庫後統計查詢的更詳細解釋,還有講解視頻分庫後的統計查詢梳理要點和難點。集算器還很容易嵌入到Java應用程序中,Java 如何調用 SPL 腳本 有使用和獲得它的方法。關於集算器安裝使用、獲得免費授權和相關技術資料,可以參見 集算器如何使用 。
Ⅲ 分庫分表技術及技術方案
一、分庫分表的必要性
分庫分表技術的使用,主要是資料庫產生了瓶頸,如單庫的並發訪問或單表的查詢都超出了閾值。對系統使用造成一定的影響,不得已而產生的技術。
通過分庫分表技術來解決此類問題,但正因為使用此技術,會產生ACID一系列的問題,各類中間件解決此類問題各有各的優勢。
提示:如場景無必要,千萬不要使用分庫分表。
二、分庫分表的思路
1、垂直區分
垂直分庫:從業務角度,一個庫分成多個庫,如把訂單和用戶信息分成兩個庫來存儲。這樣的好處就是可以微服務了。每塊的業務單獨部署,互不影響,通過介面去調用。
垂直分表:把大表分成多個小表,如熱點數據和非熱點數據分開,提高查詢速度。
2、水平區分
水平分表:同一業務如數據量大了以後,根據一定的規則分為不同的表進行存儲。
水平分庫:如訂單分成多個庫存儲,分解伺服器壓力。
以上一般來說,垂直分庫和水平分表用的會多些。
三、分庫分表的原理分析
分庫分表常用的方案:Hash取模方案和range范圍方案;
路由演算法為最主要的演算法,指得是把路由的Key按照指定的演算法進行存放;
1、Hash取模方案
根據取余分配到不同的表裡。要根據實際情況確認模的大小。此方案由於平均分配,不存在熱點問題,但數據遷移很復雜。
2、Range范圍方案
range根據范圍進行劃分,如日期,大小。此方案不存在數據遷移,但存在熱點問題。
四、分庫分表的技術選型
1、技術選型
解決方案主要分為4種:MySQL的分區技術、NoSql、NewSQL、MySQL的分庫分表。
(1)mysql分區技術:把一張表存放在不同存儲文件。由於無法負載,使用較少。
(2)NoSQL(如MongoDB):如是訂單等比較重要數據,強關聯關系,需約束一致性,不太適應。
(3)NewSql(具有NoSQL對海量數據的存儲管理能力,還保持了傳統資料庫支持ACID和SQL等特性):如TiDB可滿足需求。
(4)MySQL的分庫分表:如使用mysql,此種方案為主流方式。
2、中間件
解決此類問題的中間件主要為:Proxy模式、Client模式。
(1)Proxy模式
(2)Client模式
把分庫分表相關邏輯存放在客戶端,一版客戶端的應用會引用一個jar,然後再jar中處理SQL組合、資料庫路由、執行結果合並等相關功能。
(3)中間件的比較
由於Client模式少了一層,運維方便,相對來說容易些。
五、分庫分表的實踐
根據容量(當前容量和增長量)評估分庫或分表個數 -> 選key(均勻)-> 分表規則(hash或range等)-> 執行(一般雙寫)-> 擴容問題(盡量減少數據的移動)。
在這里我們選用中間件share-jdbc。
1、引入maven依賴
2、spring boot規則配置
行表達式標識符可以使用${...}或$->{...},但前者與Spring本身的屬性文件佔位符沖突,因此在Spring環境中使用行表達式標識符建議使用$->{...}。
3、創建DataSource
通過ShardingDataSourceFactory工廠和規則配置對象獲取ShardingDataSource,ShardingDataSource實現自JDBC的標准介面DataSource。然後即可通過DataSource選擇使用原生JDBC開發,或者使用JPA, MyBatis等ORM工具。
Ⅳ sql語句分幾類,sql資料庫都有哪幾種數據類型
一、 整數數據類型
整數數據類型是最常用的數據類型之一。
1、INT (INTEGER)
INT (或INTEGER)數據類型存儲從-2的31次方 (-2 ,147 ,483 ,648) 到2的31次方-1 (2 ,147 ,483,647) 之間的所有正負整數。每個INT 類型的數據按4 個位元組存儲,其中1 位表示整數值的正負號,其它31 位表示整數值的長度和大小。
2、SMALLINT
SMALLINT 數據類型存儲從-2的15次方( -32, 768) 到2的15次方-1( 32 ,767 )之間的所有正負整數。每個SMALLINT 類型的數據佔用2 個位元組的存儲空間,其中1 位表示整數值的正負號,其它15 位表示整數值的長度和大小。
3、TINYINT
TINYINT數據類型存儲從0 到255 之間的所有正整數。每個TINYINT類型的數據佔用1 個位元組的存儲空間。
4、BIGINT
BIGINT 數據類型存儲從-2^63 (-9 ,223, 372, 036, 854, 775, 807) 到2^63-1( 9, 223, 372, 036 ,854 ,775, 807) 之間的所有正負整數。每個BIGINT 類型的數據佔用8個位元組的存儲空間。
二、 浮點數據類型
浮點數據類型用於存儲十進制小數。浮點數值的數據在SQL Server 中採用上舍入(Round up 或稱為只入不舍)方式進行存儲。所謂上舍入是指,當(且僅當)要舍入的數是一個非零數時,對其保留數字部分的最低有效位上的數值加1 ,並進行必要的進位。若一個數是上舍入數,其絕對值不會減少。如:對3.14159265358979 分別進行2 位和12位舍入,結果為3.15 和3.141592653590。
1、REAL 數據類型
REAL數據類型可精確到第7 位小數,其范圍為從-3.40E -38 到3.40E +38。 每個REAL類型的數據佔用4 個位元組的存儲空間。
2、FLOAT
FLOAT數據類型可精確到第15 位小數,其范圍為從-1.79E -308 到1.79E +308。 每個FLOAT 類型的數據佔用8 個位元組的存儲空間。 FLOAT數據類型可寫為FLOAT[ n ]的形式。n 指定FLOAT 數據的精度。n 為1到15 之間的整數值。當n 取1 到7 時,實際上是定義了一個REAL 類型的數據,系統用4 個位元組存儲它;當n 取8 到15 時,系統認為其是FLOAT 類型,用8 個位元組存儲它。
3、DECIMAL
DECIMAL數據類型可以提供小數所需要的實際存儲空間,但也有一定的限制,您可以用2 到17 個位元組來存儲從-10的38次方-1 到10的38次方-1 之間的數值。可將其寫為DECIMAL[ p [s] ]的形式,p 和s 確定了精確的比例和數位。其中p 表示可供存儲的值的總位數(不包括小數點),預設值為18; s 表示小數點後的位數,預設值為0。 例如:decimal (15 5),表示共有15 位數,其中整數10 位,小數5。 位表4-3 列出了各精確度所需的位元組數之間的關系。
Ⅳ sqlserver中分表和分庫有什麼區別
MS SQL Server:分區表、分區索引 詳解
1. 分區表簡介
使用分區表的主要目的,是為了改善大型表以及具有各種訪問模式的表的可伸縮性和可管理性。
大型表:數據量巨大的表。
訪問模式:因目的不同,需訪問的不同的數據行集,每種目的的訪問可以稱之為一種訪問模式。
分區一方面可以將數據分為更小、更易管理的部分,為提高性能起到一定的作用;另一方面,對於如果具有多個CPU的系統,分區可以是對表的操作通過並行的方式進行,這對於提升性能是非常有幫助的。
注意:只能在 SQL Server Enterprise Edition 中創建分區函數。只有 SQL Server Enterprise Edition 支持分區。
2. 創建分區表或分區索引的步驟
可以分為以下步驟:
1. 確定分區列和分區數
2. 確定是否使用多個文件組
3. 創建分區函數
4. 創建分區架構(Schema)
5. 創建分區表
6. 創建分區索引
下面詳細描述的創建分區表、分區索引的步驟。
2.1. 確定分區列和分區數
在開始做分區操作之前,首先要確定待分區表的訪問模式,該模式決定了什麼列適合做分區鍵。例如,對於銷售數據,一般會先根據日期把數據范圍限定在一個范圍內,然後在這個基礎上做進一步的查詢,這樣,就可以把日期作為分區列。
確定了分區列之後,需要進一步確定分區數,亦即分區表中需要包含多少數據,每個分區的數據應該限定在哪個范圍。
2.2. 確定是否使用多個文件組
為了有助於優化性能和維護,應該使用文件組分離數據。一般情況下,如果經常對分區的整個數據集操作,則文件組數最好與分區數相同,並且這些文件組通常應該位於不同的磁碟上,再配合多個CPU,則SQL Server 可以並行處理多個分區,從而大大縮短處理大量復雜報表和分析的總體時間。
2.3. 創建分區函數
分區函數用於定義分區的邊界條件,創建分區函數的語法如下:
CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )
AS RANGE [ LEFT | RIGHT ]
FOR VALUES ( [ boundary_value [ ,...n ] ] )
[ ; ]
參數說明:
partition_function_name
是分區函數的名稱。分區函數名稱在資料庫內必須唯一,並且符合標識符的規則。
input_parameter_type
是用於分區的列的數據類型。當用作分區列時,除 text、ntext、image、xml、timestamp、varchar(max)、nvarchar(max)、varbinary(max)、別名數據類型或 CLR 用戶定義數據類型外,所有數據類型均有效。
實際列(也稱為分區列)是在 CREATE TABLE 或 CREATE INDEX 語句中指定的。
boundary_value
為使用 partition_function_name 的已分區表或索引的每個分區指定邊界值。如果 boundary_value 為空,則分區函數使用 partition_function_name 將整個表或索引映射到單個分區。只能使用 CREATE TABLE 或 CREATE INDEX 語句中指定的一個分區列。
boundary_value 是可以引用變數的常量表達式。這包括用戶定義類型變數,或函數以及用戶定義函數。它不能引用 Transact-SQL 表達式。boundary_value 必須與 input_parameter_type 中提供的數據類型相匹配或者可隱式轉換為該數據類型,並且如果該值的大小和小數位數與 input_parameter_type 中相應的值的大小和小數位數不匹配,則在隱式轉換過程中該值不能被截斷。
注意:
如果 boundary_value 包含 datetime 或 smalldatetime 文字值,則為這些文字值在計算時假設 us_english 是會話語言。不推薦使用此行為。要確保分區函數定義對於所有會話語言都具有預期的行為,建議使用對於所有語言設置都以相同方式進行解釋的常量,例如 yyyymmdd 格式;或者將文字值顯式轉換為特定樣式。有關詳細信息,請參閱編寫國際化 Transact-SQL 語句。若要確定伺服器的語言會話,請運行 SELECT @@LANGUAGE。
...n
指定 boundary_value 提供的值的數目,不能超過 999。所創建的分區數等於 n + 1。不必按順序列出各值。如果值未按順序列出,則 Microsoft SQL Server 2005 資料庫引擎將對它們進行排序,創建函數並返回一個警告,說明未按順序提供值。如果 n 包括任何重復的值,則資料庫引擎將返回錯誤。
LEFT | RIGHT
指定當間隔值由 資料庫引擎 按升序從左到右排序時,boundary_value [ ,...n ] 屬於每個邊界值間隔的哪一側(左側還是右側)。如果未指定,則默認值為 LEFT。
創建分區函數示例:
CREATE PARTITION FUNCTION PF_Left(int)
AS RANGE LEFT
FOR VALUES(10, 20)
GO
CREATE PARTITION FUNCTION PF_Right(int)
AS RANGE LEFT
FOR VALUES(10, 20)
GO
PF_Left 和 PF_Right 分區函數的區分:
分區函數 分區1 分區2 分區3
PF_Left <= 10 > 10 and <= 20 > 20
PF_Right < 10 >= 10 and < 20 >= 20
2.4. 創建分區架構(Schema)
創建分區函數後,必須將其與分區架構(Schema)相關聯,以便將分區定向至特定的文件組。定義分區架構師,即使多個分區位於同一個文件組中,也必須為每個分區指定一個文件組。
創建分區架構的語法如下:
GOCREATE PARTITION SCHEME partition_scheme_name
AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )
[ ; ]
參數:
partition_scheme_name
分區方案的名稱。分區方案名稱在資料庫中必須是唯一的,並且符合標識符規則。
partition_function_name
使用分區方案的分區函數的名稱。分區函數所創建的分區將映射到在分區方案中指定的文件組。partition_function_name 必須已經存在於資料庫中。
ALL
指定所有分區都映射到在 file_group_name 中提供的文件組,或映射到主文件組(如果指定了 [PRIMARY]。如果指定了 ALL,則只能指定一個 file_group_name。
file_group_name | [ PRIMARY ] [ ,...n]
指定用來持有由 partition_function_name 指定的分區的文件組的名稱。file_group_name 必須已經存在於資料庫中。
如果指定了 [PRIMARY],則分區將存儲於主文件組中。如果指定了 ALL,則只能指定一個 file_group_name。分區分配到文件組的順序是從分區 1 開始,按文件組在 [,...n] 中列出的順序進行分配。在 [,...n] 中,可以多次指定同一個 file_group_name。如果 n 不足以擁有在 partition_function_name 中指定的分區數,則 CREATE PARTITION SCHEME 將失敗,並返回錯誤。
如果 partition_function_name 生成的分區數少於文件組數,則第一個未分配的文件組將標記為 NEXT USED,並且出現顯示命名 NEXT USED 文件組的信息。如果指定了 ALL,則單獨的 file_group_name 將為該 partition_function_name 保持它的 NEXT USED 屬性。如果在 ALTER PARTITION FUNCTION 語句中創建了一個分區,則 NEXT USED 文件組將再接收一個分區。若要再創建一個未分配的文件組來擁有新的分區,請使用 ALTER PARTITION SCHEME。
在 file_group_name[ 1,...n] 中指定主文件組時,必須像在 [PRIMARY] 中那樣分隔 PRIMARY,因為它是關鍵字。
創建分區架構示例:
CREATE PARTITION FUNCTION myRangePF1 (int)
AS RANGE LEFT FOR VALUES (1, 100, 1000);
GO
CREATE PARTITION SCHEME myRangePS1
AS PARTITION myRangePF1
TO (test1fg, test2fg, test3fg, test4fg);
GO
2.5. 創建分區表
定義了分區函數(邏輯結構)和分區架構(物理結構)後,既可以創建分區表來利用它們。分區表定義應使用的分區架構,而分區架構又定義其使用的分區函數。要將這三者結合起來,必須指定應用於分區函數的列 。范圍分區始終只映射到表中的一列。
CREATE TABLE 語法如下:
CREATE TABLE
[ database_name . [ schema_name ] . | schema_name . ] table_name
( { <column_definition> | <computed_column_definition> }
[ <table_constraint> ] [ ,...n ] )
[ ON { partition_scheme_name ( partition_column_name ) | filegroup
| "default" } ]
[ { TEXTIMAGE_ON { filegroup | "default" } ]
[ ; ]
示例如下:
CREATE TABLE myRangePT1
(
ID int not null,
AGE int,
PRIMARY KEY (ID)
) ON myRangePS1(myRangePF1)
GO
2.6. 創建分區索引
索引對於提高查詢性能非常有效,因此,一般應該考慮應該考慮為分區表建立索引,為分區表建立索引與為普通表建立索引的語法一直,但是,其行為與普通索引有所差異。
默認情況下,分區表中創建的索引使用與分區表相同分區架構和分區列,這樣,索引將於表對齊。將表與其索引對齊,可以使管理工作更容易進行,對於滑動窗口方案尤其如此。若要啟動分區切換,表的所有索引都必須對齊。
在創建索引時,也可以指定不同的分區方案(Schema)或單獨的文件組(FileGroup)來存儲索引,這樣SQL Server 不會將索引與表對齊。
在已分區的表上創建索引(分區索引)時,應該注意以下事項:
唯一索引
建立唯一索引(聚集或者非聚集)時,分區列必須出現在索引列中。此限制將使SQL Server只調查單個分區,並確保表中寵物的新鍵值。如果分區依據列不可能包含在唯一鍵中,則必須使用DML觸發器,而不是強制實現唯一性。
非唯一索引
對非唯一的聚集索引進行分區時,如果未在聚集鍵中明確指定分區依據列,默認情況下SQL Server 將在聚集索引列中添加分區依據列。
對非唯一的非聚集索引進行分區時,默認情況下SQL Server 將分區依據列添加為索引的包含性列,以確保索引與基表對齊,若果索引中已經存在分區依據列,SQL Server 將不會像索引中添加分區依據列。
3. 分區操作
分區適用於可以縮放的大型表,所以隨著時間和環境的變化,就會產生對分區的拆分、合並、移動的需求。
3.1. 拆分與合並分區
通過拆分或合並邊界值更改分區函數。通過執行 ALTER PARTITION FUNCTION,可以將使用分區函數的任何錶或索引的某個分區拆分為兩個分區,也可以將兩個分區合並為一個分區。
注意:多個表或索引可以使用同一分區函數。ALTER PARTITION FUNCTION 在單個事務中影響所有這些表或索引。
ALTER PARTITION FUNCTION 語法如下:
ALTER PARTITION FUNCTION partition_function_name()
{
SPLIT RANGE ( boundary_value )
| MERGE RANGE ( boundary_value )
} [ ; ]
參數說明:
partition_function_name
要修改的分區函數的名稱。
SPLIT RANGE ( boundary_value )
在分區函數中添加一個分區。boundary_value 確定新分區的范圍,因此它必須不同於分區函數的現有邊界范圍。根據 boundary_value,Microsoft SQL Server 2005 資料庫引擎將某個現有范圍拆分為兩個范圍。在這兩個范圍中,新 boundary_value 所在的范圍被視為是新分區。
重要提示:
文件組必須處於聯機狀態,並且必須由使用此分區函數的分區方案標記為 NEXT USED,以保存新分區。在 CREATE PARTITION SCHEME 語句中,將把文件組分配給分區。如果 CREATE PARTITION SCHEME 語句分配了多餘的文件組(在 CREATE PARTITION FUNCTION 語句中創建的分區數少於用於保存它們的文件組),則存在未分配的文件組,分區方案將把其中的某個文件組標記為 NEXT USED。該文件組將保存新的分區。如果分區方案未將任何文件組標記為 NEXT USED,則必須使用 ALTER PARTITION SCHEME 添加一個文件組或指定一個現有文件組來保存新分區。可以指定已保存分區的文件組來保存附加分區。由於一個分區函數可以參與多個分區方案,因此所有使用分區函數(您向其中添加了分區)的分區方案都必須擁有一個 NEXT USED 文件組。否則,ALTER PARTITION FUNCTION 將失敗並出現錯誤,該錯誤顯示缺少 NEXT USED 文件組的一個或多個分區方案。
MERGE [ RANGE ( boundary_value) ]
刪除一個分區並將該分區中存在的所有值都合並到剩餘的某個分區中。RANGE (boundary_value) 必須是一個現有邊界值,已刪除分區中的值將合並到該值中。如果最初保存 boundary_value 的文件組沒有被剩餘分區使用,也沒有使用 NEXT USED 屬性進行標記,則將從分區方案中刪除該文件組。合並的分區駐留在最初不保存 boundary_value 的文件組中。boundary_value 是一個可以引用變數(包括用戶定義類型變數)或函數(包括用戶定義函數)的常量表達式。它無法引用 Transact-SQL 表達式。boundary_value 必須匹配或可以隱式轉換為其對應列的數據類型,並且當值的大小和小數位數不匹配其對應 input_parameter_type 時,將無法在隱式轉換過程中被截斷。
Ⅵ 資料庫為什麼要分庫分表,資料庫分庫分表
1 基本思想之什麼是分庫分表?
從字面上簡單理解,就是把原本存儲於一個庫的數據分塊存儲到多個庫上,把原本存儲於一個表的數據分塊存儲到多個表上。
2 基本思想之為什麼要分庫分表?
數
據庫中的數據量不一定是可控的,在未進行分庫分表的情況下,隨著時間和業務的發展,庫中的表會越來越多,表中的數據量也會越來越大,相應地,數據操作,增
刪改查的開銷也會越來越大;另外,由於無法進行分布式式部署,而一台伺服器的資源(CPU、磁碟、內存、IO等)是有限的,最終資料庫所能承載的數據量、
數據處理能力都將遭遇瓶頸。
3 分庫分表的實施策略。
分庫分表有垂直切分和水平切分兩種。
3.1
何謂垂直切分,即將表按照功能模塊、關系密切程度劃分出來,部署到不同的庫上。例如,我們會建立定義資料庫workDB、商品資料庫payDB、用戶數據
庫userDB、日誌資料庫logDB等,分別用於存儲項目數據定義表、商品定義表、用戶數據表、日誌數據表等。
3.2
何謂水平切分,當一個表中的數據量過大時,我們可以把該表的數據按照某種規則,例如userID散列,進行劃分,然後存儲到多個結構相同的表,和不同的庫
上。例如,我們的userDB中的用戶數據表中,每一個表的數據量都很大,就可以把userDB切分為結構相同的多個userDB:part0DB、
part1DB等,再將userDB上的用戶數據表userTable,切分為很多userTable:userTable0、userTable1等,
然後將這些表按照一定的規則存儲到多個userDB上。
3.3 應該使用哪一種方式來實施資料庫分庫分表,這要看資料庫中數據量的瓶頸所在,並綜合項目的業務類型進行考慮。
如果資料庫是因為表太多而造成海量數據,並且項目的各項業務邏輯劃分清晰、低耦合,那麼規則簡單明了、容易實施的垂直切分必是首選。
而
如果資料庫中的表並不多,但單表的數據量很大、或數據熱度很高,這種情況之下就應該選擇水平切分,水平切分比垂直切分要復雜一些,它將原本邏輯上屬於一體
的數據進行了物理分割,除了在分割時要對分割的粒度做好評估,考慮數據平均和負載平均,後期也將對項目人員及應用程序產生額外的數據管理負擔。
在現實項目中,往往是這兩種情況兼而有之,這就需要做出權衡,甚至既需要垂直切分,又需要水平切分。我們的游戲項目便綜合使用了垂直與水平切分,我們首先對資料庫進行垂直切分,然後,再針對一部分表,通常是用戶數據表,進行水平切分。
4 分庫分表存在的問題。
4.1 事務問題。
在執行分庫分表之後,由於數據存儲到了不同的庫上,資料庫事務管理出現了困難。如果依賴資料庫本身的分布式事務管理功能去執行事務,將付出高昂的性能代價;如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔。
4.2 跨庫跨表的join問題。
在執行了分庫分表之後,難以避免會將原本邏輯關聯性很強的數據劃分到不同的表、不同的庫上,這時,表的關聯操作將受到限制,我們無法join位於不同分庫的表,也無法join分表粒度不同的表,結果原本一次查詢能夠完成的業務,可能需要多次查詢才能完成。
4.3 額外的數據管理負擔和數據運算壓力。
額
外的數據管理負擔,最顯而易見的就是數據的定位問題和數據的增刪改查的重復執行問題,這些都可以通過應用程序解決,但必然引起額外的邏輯運算,例如,對於
一個記錄用戶成績的用戶數據表userTable,業務要求查出成績最好的100位,在進行分表之前,只需一個order
by語句就可以搞定,但是在進行分表之後,將需要n個order
by語句,分別查出每一個分表的前100名用戶數據,然後再對這些數據進行合並計算,才能得出結果。
Ⅶ 資料庫分庫分表 sql需要重寫嗎
如果有數據路由功能的中間件,分庫分表後應用程序可以避免修改。
比如mysql 的proxy 、 mycat 等。
一般分庫分表也都要使用這些工具,不然對開發的程序侵入性太大,也不好維護。
Ⅷ 分庫分表 VS newsql資料庫
最近與同行 科技 交流,經常被問到分庫分表與分布式資料庫如何選擇,網上也有很多關於中間件+傳統關系資料庫(分庫分表)與NewSQL分布式資料庫的文章,但有些觀點與判斷是我覺得是偏激的,脫離環境去評價方案好壞其實有失公允。
本文通過對兩種模式關鍵特性實現原理對比,希望可以盡可能客觀、中立的闡明各自真實的優缺點以及適用場景。
首先關於「中間件+關系資料庫分庫分表」算不算NewSQL分布式資料庫問題,國外有篇論文pavlo-newsql-sigmodrec,如果根據該文中的分類,Spanner、TiDB、OB算是第一種新架構型,Sharding-Sphere、Mycat、DRDS等中間件方案算是第二種(文中還有第三種雲資料庫,本文暫不詳細介紹)。
基於中間件(包括SDK和Proxy兩種形式)+傳統關系資料庫(分庫分表)模式是不是分布式架構?我覺得是的,因為存儲確實也分布式了,也能實現橫向擴展。但是不是"偽"分布式資料庫?從架構先進性來看,這么說也有一定道理。"偽"主要體現在中間件層與底層DB重復的SQL解析與執行計劃生成、存儲引擎基於B+Tree等,這在分布式資料庫架構中實際上冗餘低效的。為了避免引起真偽分布式資料庫的口水戰,本文中NewSQL資料庫特指這種新架構NewSQL資料庫。
NewSQL資料庫相比中間件+分庫分表的先進在哪兒?畫一個簡單的架構對比圖:
這些大多也是NewSQL資料庫產品主要宣傳的點,不過這些看起來很美好的功能是否真的如此?接下來針對以上幾點分別闡述下的我的理解。
這是把雙刃劍。
CAP限制
想想更早些出現的NoSQL資料庫為何不支持分布式事務(最新版的mongoDB等也開始支持了),是缺乏理論與實踐支撐嗎?並不是,原因是CAP定理依然是分布式資料庫頭上的頸箍咒,在保證強一致的同時必然會犧牲可用性A或分區容忍性P。為什麼大部分NoSQL不提供分布式事務?
那麼NewSQL資料庫突破CAP定理限制了嗎?並沒有。NewSQL資料庫的鼻主Google Spanner(目前絕大部分分布式資料庫都是按照Spanner架構設計的)提供了一致性和大於5個9的可用性,宣稱是一個「實際上是CA」的,其真正的含義是 系統處於 CA 狀態的概率非常高,由於網路分區導致的服務停用的概率非常小 ,究其真正原因是其打造私有全球網保證了不會出現網路中斷引發的網路分區,另外就是其高效的運維隊伍,這也是cloud spanner的賣點。詳細可見CAP提出者Eric Brewer寫的《Spanner, TrueTime 和CAP理論》。
完備性 :
兩階段提交協議是否嚴格支持ACID,各種異常場景是不是都可以覆蓋?
2PC在commit階段發送異常,其實跟最大努力一階段提交類似也會有部分可見問題,嚴格講一段時間內並不能保證A原子性和C一致性(待故障恢復後recovery機制可以保證最終的A和C)。完備的分布式事務支持並不是一件簡單的事情,需要可以應對網路以及各種硬體包括網卡、磁碟、CPU、內存、電源等各類異常,通過嚴格的測試。之前跟某友商交流,他們甚至說目前已知的NewSQL在分布式事務支持上都是不完整的,他們都有案例跑不過,圈內人士這么篤定,也說明了 分布式事務的支持完整程度其實是層次不齊的。
但分布式事務又是這些NewSQL資料庫的一個非常重要的底層機制,跨資源的DML、DDL等都依賴其實現,如果這塊的性能、完備性打折扣,上層跨分片SQL執行的正確性會受到很大影響。
性能
傳統關系資料庫也支持分布式事務XA,但為何很少有高並發場景下用呢? 因為XA的基礎兩階段提交協議存在網路開銷大,阻塞時間長、死鎖等問題,這也導致了其實際上很少大規模用在基於傳統關系資料庫的OLTP系統中。
NewSQL資料庫的分布式事務實現也仍然多基於兩階段提交協議,例如google percolator分布式事務模型,
採用原子鍾+MVCC+ Snapshot Isolation(SI),這種方式通過TSO(Timestamp Oracle)保證了全局一致性,通過MVCC避免了鎖,另外通過primary lock和secondary lock將提交的一部分轉為非同步,相比XA確實提高了分布式事務的性能。
但不管如何優化,相比於1PC,2PC多出來的GID獲取、網路開銷、prepare日誌持久化還是會帶來很大的性能損失,尤其是跨節點的數量比較多時會更加顯著,例如在銀行場景做個批量扣款,一個文件可能上W個賬戶,這樣的場景無論怎麼做還是吞吐都不會很高。
雖然NewSQL分布式資料庫產品都宣傳完備支持分布式事務,但這並不是說應用可以完全不用關心數據拆分,這些資料庫的最佳實踐中仍然會寫到,應用的大部分場景盡可能避免分布式事務。
既然強一致事務付出的性能代價太大,我們可以反思下是否真的需要這種強一致的分布式事務?尤其是在做微服務拆分後,很多系統也不太可能放在一個統一的資料庫中。嘗試將一致性要求弱化,便是柔性事務,放棄ACID(Atomicity,Consistency, Isolation, Durability),轉投BASE(Basically Available,Soft state,Eventually consistent),例如Saga、TCC、可靠消息保證最終一致等模型,對於大規模高並發OLTP場景,我個人更建議使用柔性事務而非強一致的分布式事務。關於柔性事務,筆者之前也寫過一個技術組件,最近幾年也涌現出了一些新的模型與框架(例如阿里剛開源的Fescar),限於篇幅不再贅述,有空再單獨寫篇文章。
HA與異地多活
主從模式並不是最優的方式,就算是半同步復制,在極端情況下(半同步轉非同步)也存在丟數問題,目前業界公認更好的方案是基於paxos分布式一致性協議或者其它類paxos如raft方式,Google Spanner、TiDB、cockcoachDB、OB都採用了這種方式,基於Paxos協議的多副本存儲,遵循過半寫原則,支持自動選主,解決了數據的高可靠,縮短了failover時間,提高了可用性,特別是減少了運維的工作量,這種方案技術上已經很成熟,也是NewSQL資料庫底層的標配。
當然這種方式其實也可以用在傳統關系資料庫,阿里、微信團隊等也有將MySQL存儲改造支持paxos多副本的,MySQL也推出了官方版MySQL Group Cluster,預計不遠的未來主從模式可能就成為 歷史 了。
需要注意的是很多NewSQL資料庫廠商宣傳基於paxos或raft協議可以實現【異地多活】,這個實際上是有前提的,那就是異地之間網路延遲不能太高 。以銀行「兩地三中心」為例,異地之間多相隔數千里,延時達到數十毫秒,如果要多活,那便需異地副本也參與資料庫日誌過半確認,這樣高的延時幾乎沒有OLTP系統可以接受的。
資料庫層面做異地多活是個美好的願景,但距離導致的延時目前並沒有好的方案。 之前跟螞蟻團隊交流,螞蟻異地多活的方案是在應用層通過MQ同步雙寫交易信息,異地DC將交易信息保存在分布式緩存中,一旦發生異地切換,資料庫同步中間件會告之數據延遲時間,應用從緩存中讀取交易信息,將這段時間內涉及到的業務對象例如用戶、賬戶進行黑名單管理,等數據同步追上之後再將這些業務對象從黑名單中剔除。由於雙寫的不是所有資料庫操作日誌而只是交易信息,數據延遲隻影響一段時間內數據,這是目前我覺得比較靠譜的異地度多活方案。
另外有些系統進行了單元化改造,這在paxos選主時也要結合考慮進去,這也是目前很多NewSQL資料庫欠缺的功能。
Scale橫向擴展與分片機制
paxos演算法解決了高可用、高可靠問題,並沒有解決Scale橫向擴展的問題,所以分片是必須支持的。NewSQL資料庫都是天生內置分片機制的,而且會根據每個分片的數據負載(磁碟使用率、寫入速度等)自動識別熱點,然後進行分片的分裂、數據遷移、合並,這些過程應用是無感知的,這省去了DBA的很多運維工作量。以TiDB為例,它將數據切成region,如果region到64M時,數據自動進行遷移。
分庫分表模式下需要應用設計之初就要明確各表的拆分鍵、拆分方式(range、取模、一致性哈希或者自定義路由表)、路由規則、拆分庫表數量、擴容方式等。相比NewSQL資料庫,這種模式給應用帶來了很大侵入和復雜度,這對大多數系統來說也是一大挑戰。
這里有個問題是NewSQL資料庫統一的內置分片策略(例如tidb基於range)可能並不是最高效的,因為與領域模型中的劃分要素並不一致,這導致的後果是很多交易會產生分布式事務。 舉個例子,銀行核心業務系統是以客戶為維度,也就是說客戶表、該客戶的賬戶表、流水表在絕大部分場景下是一起寫的,但如果按照各表主鍵range進行分片,這個交易並不能在一個分片上完成,這在高頻OLTP系統中會帶來性能問題。
分布式SQL支持
常見的單分片SQL,這兩者都能很好支持。NewSQL資料庫由於定位與目標是一個通用的資料庫,所以支持的SQL會更完整,包括跨分片的join、聚合等復雜SQL。中間件模式多面向應用需求設計,不過大部分也支持帶拆分鍵SQL、庫表遍歷、單庫join、聚合、排序、分頁等。但對跨庫的join以及聚合支持就不夠了。
NewSQL資料庫一般並不支持存儲過程、視圖、外鍵等功能,而中間件模式底層就是傳統關系資料庫,這些功能如果只是涉及單庫是比較容易支持的。
NewSQL資料庫往往選擇兼容MySQL或者PostgreSQL協議,所以SQL支持僅局限於這兩種,中間件例如驅動模式往往只需做簡單的SQL解析、計算路由、SQL重寫,所以可以支持更多種類的資料庫SQL。
SQL支持的差異主要在於分布式SQL執行計劃生成器,由於NewSQL資料庫具有底層數據的分布、統計信息,因此可以做CBO,生成的執行計劃效率更高,而中間件模式下沒有這些信息,往往只能基於規則RBO(Rule-Based-Opimization),這也是為什麼中間件模式一般並不支持跨庫join,因為實現了效率也往往並不高,還不如交給應用去做。
存儲引擎
傳統關系資料庫的存儲引擎設計都是面向磁碟的,大多都基於B+樹。B+樹通過降低樹的高度減少隨機讀、進而減少磁碟尋道次數,提高讀的性能,但大量的隨機寫會導致樹的分裂,從而帶來隨機寫,導致寫性能下降。NewSQL的底層存儲引擎則多採用LSM,相比B+樹LSM將對磁碟的隨機寫變成順序寫,大大提高了寫的性能。不過LSM的的讀由於需要合並數據性能比B+樹差,一般來說LSM更適合應在寫大於讀的場景。當然這只是單純數據結構角度的對比,在資料庫實際實現時還會通過SSD、緩沖、bloom filter等方式優化讀寫性能,所以讀性能基本不會下降太多。NewSQL數據由於多副本、分布式事務等開銷,相比單機關系資料庫SQL的響應時間並不佔優,但由於集群的彈性擴展,整體QPS提升還是很明顯的,這也是NewSQL資料庫廠商說分布式資料庫更看重的是吞吐,而不是單筆SQL響應時間的原因。
成熟度與生態
分布式資料庫是個新型通用底層軟體,准確的衡量與評價需要一個多維度的測試模型,需包括發展現狀、使用情況、社區生態、監控運維、周邊配套工具、功能滿足度、DBA人才、SQL兼容性、性能測試、高可用測試、在線擴容、分布式事務、隔離級別、在線DDL等等,雖然NewSQL資料庫發展經過了一定時間檢驗,但多集中在互聯網以及傳統企業非核心交易系統中,目前還處於快速迭代、規模使用不斷優化完善的階段。
相比而言,傳統關系資料庫則經過了多年的發展,通過完整的評測,在成熟度、功能、性能、周邊生態、風險把控、相關人才積累等多方面都具有明顯優勢,同時對已建系統的兼容性也更好。
對於互聯網公司,數據量的增長壓力以及追求新技術的基因會更傾向於嘗試NewSQL資料庫,不用再考慮庫表拆分、應用改造、擴容、事務一致性等問題怎麼看都是非常吸引人的方案。
對於傳統企業例如銀行這種風險意識較高的行業來說,NewSQL資料庫則可能在未來一段時間內仍處於 探索 、審慎試點的階段。基於中間件+分庫分表模式架構簡單,技術門檻更低,雖然沒有NewSQL資料庫功能全面,但大部分場景最核心的訴求也就是拆分後SQL的正確路由,而此功能中間件模式應對還是綽綽有餘的,可以說在大多數OLTP場景是夠用的。
限於篇幅,其它特性例如在線DDL、數據遷移、運維工具等特性就不在本文展開對比。
總結
如果看完以上內容,您還不知道選哪種模式,那麼結合以下幾個問題,先思考下NewSQL資料庫解決的點對於自身是不是真正的痛點:
如果以上有2到3個是肯定的,那麼你可以考慮用NewSQL資料庫了,雖然前期可能需要一定的學習成本,但它是資料庫的發展方向,未來收益也會更高,尤其是互聯網行業,隨著數據量的突飛猛進,分庫分表帶來的痛苦會與日俱增。當然選擇NewSQL資料庫你也要做好承擔一定風險的准備。
如果你還未做出抉擇,不妨再想想下面幾個問題:
如果這些問題有多數是肯定的,那還是分庫分表吧。在軟體領域很少有完美的解決方案,NewSQL資料庫也不是數據分布式架構的銀彈。相比而言分庫分表是一個代價更低、風險更小的方案,它最大程度復用傳統關系資料庫生態,通過中間件也可以滿足分庫分表後的絕大多數功能,定製化能力更強。 在當前NewSQL資料庫還未完全成熟的階段,分庫分表可以說是一個上限低但下限高的方案,尤其傳統行業的核心系統,如果你仍然打算把資料庫當做一個黑盒產品來用,踏踏實實用好分庫分表會被認為是個穩妥的選擇。
很多時候軟體選型取決於領域特徵以及架構師風格,限於筆者知識與所屬行業特點所限,以上僅為個人粗淺的一些觀點,歡迎討論。
Ⅸ 資料庫為什麼要分庫分表
1 基本思想之什麼是分庫分表?
從字面上簡單理解,就是把原本存儲於一個庫的數據分塊存儲到多個庫上,把原本存儲於一個表的數據分塊存儲到多個表上。
2 基本思想之為什麼要分庫分表?
數
據庫中的數據量不一定是可控的,在未進行分庫分表的情況下,隨著時間和業務的發展,庫中的表會越來越多,表中的數據量也會越來越大,相應地,數據操作,增
刪改查的開銷也會越來越大;另外,由於無法進行分布式式部署,而一台伺服器的資源(CPU、磁碟、內存、IO等)是有限的,最終資料庫所能承載的數據量、
數據處理能力都將遭遇瓶頸。
3 分庫分表的實施策略。
分庫分表有垂直切分和水平切分兩種。
3.1
何謂垂直切分,即將表按照功能模塊、關系密切程度劃分出來,部署到不同的庫上。例如,我們會建立定義資料庫workDB、商品資料庫payDB、用戶數據
庫userDB、日誌資料庫logDB等,分別用於存儲項目數據定義表、商品定義表、用戶數據表、日誌數據表等。
3.2
何謂水平切分,當一個表中的數據量過大時,我們可以把該表的數據按照某種規則,例如userID散列,進行劃分,然後存儲到多個結構相同的表,和不同的庫
上。例如,我們的userDB中的用戶數據表中,每一個表的數據量都很大,就可以把userDB切分為結構相同的多個userDB:part0DB、
part1DB等,再將userDB上的用戶數據表userTable,切分為很多userTable:userTable0、userTable1等,
然後將這些表按照一定的規則存儲到多個userDB上。
3.3 應該使用哪一種方式來實施資料庫分庫分表,這要看資料庫中數據量的瓶頸所在,並綜合項目的業務類型進行考慮。
如果資料庫是因為表太多而造成海量數據,並且項目的各項業務邏輯劃分清晰、低耦合,那麼規則簡單明了、容易實施的垂直切分必是首選。
而
如果資料庫中的表並不多,但單表的數據量很大、或數據熱度很高,這種情況之下就應該選擇水平切分,水平切分比垂直切分要復雜一些,它將原本邏輯上屬於一體
的數據進行了物理分割,除了在分割時要對分割的粒度做好評估,考慮數據平均和負載平均,後期也將對項目人員及應用程序產生額外的數據管理負擔。
在現實項目中,往往是這兩種情況兼而有之,這就需要做出權衡,甚至既需要垂直切分,又需要水平切分。我們的游戲項目便綜合使用了垂直與水平切分,我們首先對資料庫進行垂直切分,然後,再針對一部分表,通常是用戶數據表,進行水平切分。
4 分庫分表存在的問題。
4.1 事務問題。
在執行分庫分表之後,由於數據存儲到了不同的庫上,資料庫事務管理出現了困難。如果依賴資料庫本身的分布式事務管理功能去執行事務,將付出高昂的性能代價;如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔。
4.2 跨庫跨表的join問題。
在執行了分庫分表之後,難以避免會將原本邏輯關聯性很強的數據劃分到不同的表、不同的庫上,這時,表的關聯操作將受到限制,我們無法join位於不同分庫的表,也無法join分表粒度不同的表,結果原本一次查詢能夠完成的業務,可能需要多次查詢才能完成。
4.3 額外的數據管理負擔和數據運算壓力。
額
外的數據管理負擔,最顯而易見的就是數據的定位問題和數據的增刪改查的重復執行問題,這些都可以通過應用程序解決,但必然引起額外的邏輯運算,例如,對於
一個記錄用戶成績的用戶數據表userTable,業務要求查出成績最好的100位,在進行分表之前,只需一個order
by語句就可以搞定,但是在進行分表之後,將需要n個order
by語句,分別查出每一個分表的前100名用戶數據,然後再對這些數據進行合並計算,才能得出結果。
Ⅹ 如何實現mysql的分庫分表
1,接收到sql;2,把sql放到排隊隊列中 ;3,執行sql;4,返回執行結果。在這個執行過程中最花時間在什麼地方呢?第一,是排隊等待的時間,第二,sql的執行時間。其實這二個是一回事,等待的同時,肯定有sql在執行。所以我們要縮短sql的執行時間。
mysql中有一種機制是表鎖定和行鎖定,為什麼要出現這種機制,是為了保證數據的完整 性,我舉個例子來說吧,如果有二個sql都要修改同一張表的同一條數據,這個時候怎麼辦呢,是不是二個sql都可以同時修改這條數據呢?很顯然mysql 對這種情況的處理是,一種是表鎖定(myisam存儲引擎),一個是行鎖定(innodb存儲引擎)。表鎖定表示你們都不能對這張表進行操作,必須等我對 表操作完才行。行鎖定也一樣,別的sql必須等我對這條數據操作完了,才能對這條數據進行操作。如果數據太多,一次執行的時間太長,等待的時間就越長,這 也是我們為什麼要分表的原因。