表分區(qū)

MySQL在5.1版引入的分區(qū)是一種簡(jiǎn)單的水平拆分,用戶需要在建表的時(shí)候加上分區(qū)參數(shù),對(duì)應(yīng)用是透明的無(wú)需修改代碼

對(duì)用戶來(lái)說(shuō),分區(qū)表是一個(gè)獨(dú)立的邏輯表,但是底層由多個(gè)物理子表組成,實(shí)現(xiàn)分區(qū)的代碼實(shí)際上是通過(guò)對(duì)一組底層表的對(duì)象封裝,但對(duì)SQL層來(lái)說(shuō)是一個(gè)完全封裝底層的黑盒子。MySQL實(shí)現(xiàn)分區(qū)的方式也意味著索引也是按照分區(qū)的子表定義,沒(méi)有全局索引。

640?wx_fmt=png

用戶的SQL語(yǔ)句是需要針對(duì)分區(qū)表做優(yōu)化,SQL條件中要帶上分區(qū)條件的列,從而使查詢定位到少量的分區(qū)上,否則就會(huì)掃描全部分區(qū),可以通過(guò) EXPLAIN PARTITIONS來(lái)查看某條SQL語(yǔ)句會(huì)落在那些分區(qū)上,從而進(jìn)行SQL優(yōu)化,如下圖5條記錄落在兩個(gè)分區(qū)上:

  1. mysql> explain partitions select count(1) from user_partition where id in (1,2,3,4,5);
  2. +----+-------------+----------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
  3. | id | select_type | table          | partitions | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
  4. +----+-------------+----------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
  5. |  1 | SIMPLE      | user_partition | p1,p4      | range | PRIMARY       | PRIMARY | 8       | NULL |    5 | Using where; Using index |
  6. +----+-------------+----------------+------------+-------+---------------+---------+---------+------+------+--------------------------+
  7. 1 row in set (0.00 sec)

分區(qū)的好處是:

  • 可以讓單表存儲(chǔ)更多的數(shù)據(jù)

  • 分區(qū)表的數(shù)據(jù)更容易維護(hù),可以通過(guò)清楚整個(gè)分區(qū)批量刪除大量數(shù)據(jù),也可以增加新的分區(qū)來(lái)支持新插入的數(shù)據(jù)。另外,還可以對(duì)一個(gè)獨(dú)立分區(qū)進(jìn)行優(yōu)化、檢查、修復(fù)等操作

  • 部分查詢能夠從查詢條件確定只落在少數(shù)分區(qū)上,速度會(huì)很快

  • 分區(qū)表的數(shù)據(jù)還可以分布在不同的物理設(shè)備上,從而搞笑利用多個(gè)硬件設(shè)備

  • 可以使用分區(qū)表賴避免某些特殊瓶頸,例如InnoDB單個(gè)索引的互斥訪問(wèn)、ext3文件系統(tǒng)的inode鎖競(jìng)爭(zhēng)

  • 可以備份和恢復(fù)單個(gè)分區(qū)

分區(qū)的限制和缺點(diǎn):

  • 一個(gè)表最多只能有1024個(gè)分區(qū)

  • 如果分區(qū)字段中有主鍵或者唯一索引的列,那么所有主鍵列和唯一索引列都必須包含進(jìn)來(lái)

  • 分區(qū)表無(wú)法使用外鍵約束

  • NULL值會(huì)使分區(qū)過(guò)濾無(wú)效

  • 所有分區(qū)必須使用相同的存儲(chǔ)引擎

分區(qū)的類型:

  • RANGE分區(qū):基于屬于一個(gè)給定連續(xù)區(qū)間的列值,把多行分配給分區(qū)

  • LIST分區(qū):類似于按RANGE分區(qū),區(qū)別在于LIST分區(qū)是基于列值匹配一個(gè)離散值集合中的某個(gè)值來(lái)進(jìn)行選擇

  • HASH分區(qū):基于用戶定義的表達(dá)式的返回值來(lái)進(jìn)行選擇的分區(qū),該表達(dá)式使用將要插入到表中的這些行的列值進(jìn)行計(jì)算。這個(gè)函數(shù)可以包含MySQL中有效的、產(chǎn)生非負(fù)整數(shù)值的任何表達(dá)式

  • KEY分區(qū):類似于按HASH分區(qū),區(qū)別在于KEY分區(qū)只支持計(jì)算一列或多列,且MySQL服務(wù)器提供其自身的哈希函數(shù)。必須有一列或多列包含整數(shù)值

分區(qū)適合的場(chǎng)景有:

最適合的場(chǎng)景數(shù)據(jù)的時(shí)間序列性比較強(qiáng),則可以按時(shí)間來(lái)分區(qū),如下所示:

  1. CREATE TABLE members (
  2.    firstname VARCHAR(25) NOT NULL,
  3.    lastname VARCHAR(25) NOT NULL,/li>
  4.    username VARCHAR(16) NOT NULL,
  5.    email VARCHAR(35),
  6.    joined DATE NOT NULL
  7. )
  8. PARTITION BY RANGE( YEAR(joined) ) (
  9.    PARTITION p0 VALUES LESS THAN (1960),
  10.    PARTITION p1 VALUES LESS THAN (1970),
  11.    PARTITION p2 VALUES LESS THAN (1980),
  12.    PARTITION p3 VALUES LESS THAN (1990),
  13.    PARTITION p4 VALUES LESS THAN MAXVALUE
  14. );

查詢時(shí)加上時(shí)間范圍條件效率會(huì)非常高,同時(shí)對(duì)于不需要的歷史數(shù)據(jù)能很容的批量刪除。

如果數(shù)據(jù)有明顯的熱點(diǎn),而且除了這部分?jǐn)?shù)據(jù),其他數(shù)據(jù)很少被訪問(wèn)到,那么可以將熱點(diǎn)數(shù)據(jù)單獨(dú)放在一個(gè)分區(qū),讓這個(gè)分區(qū)的數(shù)據(jù)能夠有機(jī)會(huì)都緩存在內(nèi)存中,查詢時(shí)只訪問(wèn)一個(gè)很小的分區(qū)表,能夠有效使用索引和緩存

另外MySQL有一種早期的簡(jiǎn)單的分區(qū)實(shí)現(xiàn) - 合并表(merge table),限制較多且缺乏優(yōu)化,不建議使用,應(yīng)該用新的分區(qū)機(jī)制來(lái)替代

垂直拆分

垂直分庫(kù)是根據(jù)數(shù)據(jù)庫(kù)里面的數(shù)據(jù)表的相關(guān)性進(jìn)行拆分,比如:一個(gè)數(shù)據(jù)庫(kù)里面既存在用戶數(shù)據(jù),又存在訂單數(shù)據(jù),那么垂直拆分可以把用戶數(shù)據(jù)放到用戶庫(kù)、把訂單數(shù)據(jù)放到訂單庫(kù)。垂直分表是對(duì)數(shù)據(jù)表進(jìn)行垂直拆分的一種方式,常見(jiàn)的是把一個(gè)多字段的大表按常用字段和非常用字段進(jìn)行拆分,每個(gè)表里面的數(shù)據(jù)記錄數(shù)一般情況下是相同的,只是字段不一樣,使用主鍵關(guān)聯(lián)

比如原始的用戶表是:

20190307150113.jpg

垂直拆分后是:

20190307150158.jpg

垂直拆分的優(yōu)點(diǎn)是:

  • 可以使得行數(shù)據(jù)變小,一個(gè)數(shù)據(jù)塊(Block)就能存放更多的數(shù)據(jù),在查詢時(shí)就會(huì)減少I/O次數(shù)(每次查詢時(shí)讀取的Block 就少)

  • 可以達(dá)到最大化利用Cache的目的,具體在垂直拆分的時(shí)候可以將不常變的字段放一起,將經(jīng)常改變的放一起

  • 數(shù)據(jù)維護(hù)簡(jiǎn)單

缺點(diǎn)是:

  • 主鍵出現(xiàn)冗余,需要管理冗余列

  • 會(huì)引起表連接JOIN操作(增加CPU開(kāi)銷)可以通過(guò)在業(yè)務(wù)服務(wù)器上進(jìn)行join來(lái)減少數(shù)據(jù)庫(kù)壓力

  • 依然存在單表數(shù)據(jù)量過(guò)大的問(wèn)題(需要水平拆分)

  • 事務(wù)處理復(fù)雜

水平拆分

概述

水平拆分是通過(guò)某種策略將數(shù)據(jù)分片來(lái)存儲(chǔ),分庫(kù)內(nèi)分表和分庫(kù)兩部分,每片數(shù)據(jù)會(huì)分散到不同的MySQL表或庫(kù),達(dá)到分布式的效果,能夠支持非常大的數(shù)據(jù)量。前面的表分區(qū)本質(zhì)上也是一種特殊的庫(kù)內(nèi)分表

庫(kù)內(nèi)分表,僅僅是單純的解決了單一表數(shù)據(jù)過(guò)大的問(wèn)題,由于沒(méi)有把表的數(shù)據(jù)分布到不同的機(jī)器上,因此對(duì)于減輕MySQL服務(wù)器的壓力來(lái)說(shuō),并沒(méi)有太大的作用,大家還是競(jìng)爭(zhēng)同一個(gè)物理機(jī)上的IO、CPU、網(wǎng)絡(luò),這個(gè)就要通過(guò)分庫(kù)來(lái)解決

前面垂直拆分的用戶表如果進(jìn)行水平拆分,結(jié)果是:

20190307150227.jpg

實(shí)際情況中往往會(huì)是垂直拆分和水平拆分的結(jié)合,即將 Users_A_M和 Users_N_Z再拆成 Users和 UserExtras,這樣一共四張表

水平拆分的優(yōu)點(diǎn)是:

  • 不存在單庫(kù)大數(shù)據(jù)和高并發(fā)的性能瓶頸

  • 應(yīng)用端改造較少

  • 提高了系統(tǒng)的穩(wěn)定性和負(fù)載能力

缺點(diǎn)是:

  • 分片事務(wù)一致性難以解決

  • 跨節(jié)點(diǎn)Join性能差,邏輯復(fù)雜

  • 數(shù)據(jù)多次擴(kuò)展難度跟維護(hù)量極大

分片原則

  • 能不分就不分,參考單表優(yōu)化

  • 分片數(shù)量盡量少,分片盡量均勻分布在多個(gè)數(shù)據(jù)結(jié)點(diǎn)上,因?yàn)橐粋€(gè)查詢SQL跨分片越多,則總體性能越差,雖然要好于所有數(shù)據(jù)在一個(gè)分片的結(jié)果,只在必要的時(shí)候進(jìn)行擴(kuò)容,增加分片數(shù)量

  • 分片規(guī)則需要慎重選擇做好提前規(guī)劃,分片規(guī)則的選擇,需要考慮數(shù)據(jù)的增長(zhǎng)模式,數(shù)據(jù)的訪問(wèn)模式,分片關(guān)聯(lián)性問(wèn)題,以及分片擴(kuò)容問(wèn)題,最近的分片策略為范圍分片,枚舉分片,一致性Hash分片,這幾種分片都有利于擴(kuò)容

  • 盡量不要在一個(gè)事務(wù)中的SQL跨越多個(gè)分片,分布式事務(wù)一直是個(gè)不好處理的問(wèn)題

  • 查詢條件盡量?jī)?yōu)化,盡量避免Select * 的方式,大量數(shù)據(jù)結(jié)果集下,會(huì)消耗大量帶寬和CPU資源,查詢盡量避免返回大量結(jié)果集,并且盡量為頻繁使用的查詢語(yǔ)句建立索引。

  • 通過(guò)數(shù)據(jù)冗余和表分區(qū)賴降低跨庫(kù)Join的可能

這里特別強(qiáng)調(diào)一下分片規(guī)則的選擇問(wèn)題,如果某個(gè)表的數(shù)據(jù)有明顯的時(shí)間特征,比如訂單、交易記錄等,則他們通常比較合適用時(shí)間范圍分片,因?yàn)榫哂袝r(shí)效性的數(shù)據(jù),我們往往關(guān)注其近期的數(shù)據(jù),查詢條件中往往帶有時(shí)間字段進(jìn)行過(guò)濾,比較好的方案是,當(dāng)前活躍的數(shù)據(jù),采用跨度比較短的時(shí)間段進(jìn)行分片,而歷史性的數(shù)據(jù),則采用比較長(zhǎng)的跨度存儲(chǔ)。

總體上來(lái)說(shuō),分片的選擇是取決于最頻繁的查詢SQL的條件,因?yàn)椴粠魏蜽here語(yǔ)句的查詢SQL,會(huì)遍歷所有的分片,性能相對(duì)最差,因此這種SQL越多,對(duì)系統(tǒng)的影響越大,所以我們要盡量避免這種SQL的產(chǎn)生。