mysql數據庫分區

    日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,導致數據庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性能會更加糟糕。分表和表分區的目的就是減少數據庫的負擔,提高數據庫的效率,通常點來講就是提高表的增刪改查效率。

什麼是分表?

    分表是將一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表,我們可以稱爲子表,每個表都對應三個文件,MYD數據文件,.MYI索引文件,.frm表結構文件。這些子表可以分佈在同一塊磁盤上,也可以在不同的機器上。app讀寫的時候根據事先定義好的規則得到對應的子表名,然後去操作它。

 

什麼是分區?

    分區和分表相似,都是按照規則分解表。不同在於分表將大表分解爲若干個獨立的實體表,而分區是將數據分段劃分在多個位置存放,可以是同一塊磁盤也可以在不同的機器。分區後,表面上還是一張表,但數據散列到多個位置了。app讀寫的時候操作的還是大表名字,db自動去組織分區的數據。

 

mysql分表和分區有什麼聯繫呢?

1.都能提高mysql的性高,在高併發狀態下都有一個良好的表現。

2.分表和分區不矛盾,可以相互配合的,對於那些大訪問量,並且表數據比較多的表,我們可以採取分表和分區結合的方式(如果merge這種分表方式,不能和分區配合的話,可以用其他的分表試),訪問量不大,但是表數據很多的表,我們可以採取分區的方式等。

3.分表技術是比較麻煩的,需要手動去創建子表,app服務端讀寫時候需要計算子表名。採用merge好一些,但也要創建子表和配置子表間的union關係。

4.表分區相對於分表,操作方便,不需要創建子表。

 

分區又可以分爲兩種:

水平分區(Horizontal Partitioning)

這種形式分區是對錶的行進行分區,通過這樣的方式不同分組裏面的物理列分割的數據集得以組合,從而進行個體分割(單分區)或集體分割(1個或多個分區)。所有在表中定義的列在每個數據集中都能找到,

所以表的特性依然得以保持。

舉個簡單例子:一個包含十年發票記錄的表可以被分區爲十個不同的分區,每個分區包含的是其中一年的記錄。(注:這裏具體使用的分區方式我們後面再說,可以先說一點,一定要通過某個屬性列來分割,譬如這裏使用的列就是年份)

垂直分區(Vertical Partitioning)

這種分區方式一般來說是通過對錶的垂直劃分來減少目標表的寬度,使某些特定的列被劃分到特定的分區,每個分區都包含了其中的列所對應的行。

舉個簡單例子:一個包含了大text和BLOB列的表,這些text和BLOB列又不經常被訪問,這時候就要把這些不經常使用的text和BLOB了劃分到另一個分區,在保證它們數據相關性的同時還能提高訪問速度。

 

分區表的原理

分區表是由多個相關的底層表實現,這些底層表也是由句柄對象表示,所以我們也可以直接訪問各個分區,存儲引擎管理分區的各個底層表和管理普通表一樣(所有的底層表都必須使用相同的存儲引擎),分區表的索引只是在各個底層表上各自加上一個相同的索引,從存儲引擎的角度來看,底層表和一個普通表沒有任何不同,存儲引擎也無須知道這是一個普通表還是一個分區表的一部分。

在分區表上的操作按照下面的操作邏輯進行:

select查詢:

當查詢一個分區表的時候,分區層先打開並鎖住所有的底層表,優化器判斷是否可以過濾部分分區,然後再調用對應的存儲引擎接口訪問各個分區的數據

insert操作:

當寫入一條記錄時,分區層打開並鎖住所有的底層表,然後確定哪個分區接受這條記錄,再將記錄寫入對應的底層表

delete操作:

當刪除一條記錄時,分區層先打開並鎖住所有的底層表,然後確定數據對應的分區,最後對相應底層表進行刪除操作

update操作:

當更新一條數據時,分區層先打開並鎖住所有的底層表,mysql先確定需要更新的記錄在哪個分區,然後取出數據並更新,再判斷更新後的數據應該放在哪個分區,然後對底層表進行寫入操作,並對原數據所在的底層表進行刪除操作

雖然每個操作都會打開並鎖住所有的底層表,但這並不是說分區表在處理過程中是鎖住全表的,如果存儲引擎能夠自己實現行級鎖,如:innodb,則會在分區層釋放對應的表鎖,這個加鎖和解鎖過程與普通Innodb上的查詢類似。

 

在下面的場景中,分區可以起到非常大的作用:

A:表非常大以至於無法全部都放在內存中,或者只在表的最後部分有熱點數據,其他都是歷史數據

B:分區表的數據更容易維護,如:想批量刪除大量數據可以使用清除整個分區的方式。另外,還可以對一個獨立分區進行優化、檢查、修復等操作

C:分區表的數據可以分佈在不同的物理設備上,從而高效地利用多個硬件設備

D:可以使用分區表來避免某些特殊的瓶頸,如:innodb的單個索引的互斥訪問,ext3文件系統的inode鎖競爭等

E:如果需要,還可以備份和恢復獨立的分區,這在非常大的數據集的場景下效果非常好

F:優化查詢,在where字句中包含分區列時,可以只使用必要的分區來提高查詢效率,同時在涉及sum()和count()這類聚合函數的查詢時,可以在每個分區上面並行處理,最終只需要彙總所有分區得到的結果。

mysql數據庫的分區總是把null當作比任何非null更小的值,這和數據庫中處理null值的order by操作是一樣的,升序排序時null總是在最前面,因此對於不同的分區類型,mysql數據庫對於null的處理也各不相同。對於range分區,如果向分區列插入了null,則mysql數據庫會將該值放入最左邊的分區,注意,如果刪除分區,分區下的所有內容都從磁盤中刪掉了,null所在分區被刪除,null值也就跟着被刪除了。在list分區下要使用null,則必須顯式地定義在分區的散列值中,否則插入null時會報錯。hash和key分區對於null的處理方式和range,list分區不一樣,任何分區函數都會將null返回爲0.

 

分區

分區就是將數據庫或其構成元素劃分爲不同的獨立部分

--是一種預先組織表存儲的方法

mysql支持水平分區

將特定錶行分配爲行的子集

分區的分佈是跨物理存儲進行的

--根據用戶在需要時設置的指定規則

--每個分區存儲爲其自己的單元

數據的劃分

--根據分區功能將數據劃分爲子集

--分區類型和表達式是表定義的一部分

--表達式可以是整數或返回整數值的函數。

--此值根據定義確定將每條記錄存儲在哪個分區中

1.primary key和unique key必須包含在分區key的一部分,否則在創建primary key和unique index時會報”ERROR 1503 (HY000)“

2.範圍分區添加分區只能在最大值後面追加分區

3.所有分區的engine必須一樣

4.範圍分區分區字段:integer、數值表達式、日期列,日期函數表達式(如year(),to_days(),to_seconds(),unix_timestamp())

 

分表的幾種方式:

1、mysql集羣

它並不是分表,但起到了和分表相同的作用。集羣可分擔數據庫的操作次數,將任務分擔到多臺數據庫上。集羣可以讀寫分離,減少讀寫壓力。從而提升數據庫性能。

2、自定義規則分表

分區的類型

range 根據屬於指定範圍的列值將行分配到分區

list 根據與離散值集之一匹配的列將行分配到分區

hash 基於由用戶定義的表達式返回的值而選擇的分區,對要插入表中的行的列值進行操作

key 與hash類似,不同之處在於僅提供要評估的一個或多個列

Composite(複合模式) –以上模式的組合使用 

InnoDB foreign keys and MySQL partitioning are not compatible. Partitioned InnoDB tables cannot have foreign key references, nor can they have columns referenced by foreign keys. InnoDB tables which have or which are referenced by foreign keys cannot be partitioned.

分區的幾種方式實踐:

Range:
create table range(
  id int(11),
  money int(11) unsigned not null,
  date datetime
  )partition by range(year(date))(
  partition p2007 values less than (2008),
  partition p2008 values less than (2009),
  partition p2009 values less than (2010)
  partition p2010 values less than maxvalue
);
List:

create table list(
  a int(11),
  b int(11)
  )(partition by list (b)
  partition p0 values in (1,3,5,7,9),
  partition p1 values in (2,4,6,8,0)
 );
Hash:

create table hash(
  a int(11),
  b datetime
  )partition by hash (YEAR(b)
  partitions 4;
Key:

create table t_key(
  a int(11),
  b datetime)
  partition by key (b)
  partitions 4;

分區管理

新增分區

ALTER TABLE sale_data
ADD PARTITION (PARTITION p201010 VALUES LESS THAN (201011));

刪除分區

--當刪除了一個分區,也同時刪除了該分區中所有的數據。
ALTER TABLE sale_data DROP PARTITION p201010;

分區的合併

下面的SQL,將p201001 - p201009 合併爲3個分區p2010Q1 - p2010Q3

ALTER TABLE sale_data
REORGANIZE PARTITION p201001,p201002,p201003,
p201004,p201005,p201006,
p201007,p201008,p201009 INTO
(
PARTITION p2010Q1 VALUES LESS THAN (201004),
PARTITION p2010Q2 VALUES LESS THAN (201007),
PARTITION p2010Q3 VALUES LESS THAN (201010)
);

轉載鏈接:https://www.zhihu.com/question/38418707/answer/579911085

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章