分區表
主要提供如下的特性,或者適合如此場景:
- 數據量非常大, 或者只有表中最後的部分有熱點數據,其他均爲歷史數據
- 分區表數據更容易維護,可以對獨立的分區刪除等操作
- 分區表的數據可以分佈在不同的物理設備上,從而高效地利用多個硬件設備。
- 可以避免一些特殊瓶頸,比如InnoDB的單個索引的互斥訪問
- 可以備份和恢復獨立的分區
創建分區表
通常有這麼幾種分法,因爲主鍵或者是唯一約束鍵必須有一部分包含在分區鍵中,所以一般要不無主鍵,要不就按照自增主鍵的id進行範圍分區,要不就把分區字段和主鍵一起作爲聯合主鍵。
還有一些其他的限制,比如分區鍵的運算結果必須爲整數
Range分區
CREATE TABLE biz_order(
id bigint(20) NOT NULL AUTO_INCREMENT,
created DATETIME NOT NULL COMMENT '創建時間',
PRIMARY KEY (id, created)) ENGINE=InnoDB PARTITION BY RANGE(YEAR(created))(
PARTITION p_2010 VALUES LESS THAN (2015),
PARTITION p_latest VALUES LESS THAN MAXVALUE);
這種分區,最新的那個區顯然會有最多的熱點數據。 可以再使用Hash子分區來減少競爭
- 除了使用YEAR, TO_DAY等日期函數外,還可以使用其數學函數,比如取模,按7取模是周幾等
List分區
是用IN來做列值匹配的集合。 比如可以按照地區來分爲東西南北幾個區:
PARTITION BY LIST(store_id)
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
這種如果插入語句不在IN中,則會插入失敗
Hash分區
PARTITIONS爲分區的數量, 即會根據分區鍵的值計算出一個hash值,然後以4爲模進行存儲,好處是,不用再重新建分區了。
PARTITION BY HASH(store_id)
PARTITIONS 4;
還有Key分區,用的太少,不說了
操作分區表
增加刪除分區等語句看這裏
分區表由多個底層表構成,底層表跟普通表沒什麼區別,其索引也是分別在各個表中的索引。 分區表只是會在一個很粗的粒度上決定一下去哪個底層表繼續查詢。
- SELECT 鎖住底層表,優化器先判斷可以過濾部分的分期,然後再調用存儲引擎接口訪問各個分區
- INSERT DELETE同行
- UPDATE 操作會需要設計更新後判斷在哪個分區,如果插入到了新分區,那麼則刪除原分區中的數據。
- 使用WHERE語句最好能夠明確用到分區的關鍵字,這樣可以很好的命中分區
- 鎖住底層表不一定是表鎖,會用到存儲引擎自己的行級鎖
如何使用
使用分區表肯定是因爲數據量非常大,這個時候索引已經不能很好的起作用了。
可以不使用索引,而用粗粒度的命中分區表,然後全表掃描。
或者是針對熱點數據,單獨使用一個區讓這個區都能夠放到緩存中,這樣就會有一個熱點的很小的分區,可以對其使用索引。
另外一些可能的問題:
- NULL值,因爲TO_DAY等方法NULL值爲無效入參,會把值放在第一個分區,這個時候SELECT的時候可能會需要查找第一個和命中的分區這樣兩個分區,這樣可能會有很多的性能損耗,解決辦法是使第一個分區儘可能的小,第二個辦法是直接使用RANGE COLUMNS()而不使用函數
- 分區列和索引列應該用同一個列,如果不是,會導致無法過濾的問題
- 尋找分區的成本可能會比較高
- 維護分區的成本,比如alter等語句改變分區個數,或者其他涉及數據遷移的操作
分區表的查詢
要在WHERE後面帶分區列,且不能是表達式
使用EXPLAIN PARTITIONS SELECT來判斷是否進行了分區過濾
分表
分區表還是一張表,是一種邏輯上的實現,主要解決的是單表數據過大,索引效率低的問題,很適合大量歷史數據,少量活躍數據的場景。把數據保存在不同的區域。
分表是真的有多張表,基於分表還可以做分庫,可以提升併發性能,以及磁盤I/O的性能。
二者可以配合使用。
使用集羣的方式
要配合複製使用,僅僅是把查詢請求進行了分攤。
但是這樣不會影響代碼層。
使用業務邏輯劃分
可一個根據用戶id來分,每個用戶一張表,這樣需要每有新的用戶都建表了。
還有常用的做法是預先設計好比如100張表,然後對數據的一個字段做hash,然後對100取模。
又或者根據時間來進行分割,這種的好處是,如果根據時間做統計的時候可以不用UNION
上面的分表方式都不能解決根據服務器壓力進行選擇的問你,並且也不能比較均勻的保存數據。
分表之後要考慮這樣幾個操作以後可能會帶來的問題:
- 分頁, 主要看分頁情況下排序的字段是什麼,如果是時間,那麼按照時間段分表是比較好的, 如果會涉及到多個表的UNION,那麼就會比較耗費性能。
- 插入, 更新。 主要是更新的時候的主鍵的問題,因爲分表之後主鍵不唯一了,因此需要用分表列和自增列做聯合主鍵。
- 分組,統計。 這個跟分頁考慮的情況差不多,也是主要涉及排序的問題。比如如果每次都是需要按照用戶統計信息的話,那麼按照用戶分表的選擇是沒錯的。
- 表的分發跟業務很比較大的關係。要儘量考慮比較多的因素和場景。
- 通用一些的解決辦法是,對分頁字段使用搜索引擎
- 或者對分頁和排序字段單獨列一張表不分,作爲查詢的索引。
使用merge存儲引擎
基本表:
CREATE TABLE TEST_MERGE_1(
ID INT(5) NOT NULL,
VALUE VARCHAR(100) NOT NULL,
PRIMARY KEY(ID)
);
CREATE TABLE TEST_MERGE_2(
ID INT(5) NOT NULL,
VALUE VARCHAR(100) NOT NULL,
PRIMARY KEY(ID)
);
MERGE表:
CREATE TABLE TEST_MERGE(
ID INT(5) NOT NULL,
VALUE VARCHAR(100) NOT NULL,
PRIMARY KEY(ID)
) TYPE=MRG_MyISAM INSERT_METHOD=LAST UNION=(TEST_MERGE_1,TEST_MERGE_2);
基本表必須是MYISAM類型的。
基本表的數據結構必須一致。
order by等語句,我想的是因爲Merge表裏有基本表共同的索引,所以,排序的時候應該是,都先比較第一個,然後再。。。有點像常用的大文件分成多個小文件,然後分別排序,最後merge的過程。
主要是能夠提供比較好的編碼界面。