一、爲何要分表?
數據庫數據愈來愈大,隨之而來的是單個表中數據太多。以致於查詢速度變慢,並且因爲表的鎖機制致使應用操做也搜到嚴重影響,出現了數據庫性能瓶頸。
mysql中有一種機制是表鎖定和行鎖定,是爲了保證數據的完整性。表鎖定表示大家都不能對這張表進行操做,必須等我對錶操做完才行。行鎖定也同樣,別的sql必須等我對這條數據操做完了,才能對這條數據進行操做。當出現這種狀況時,咱們能夠考慮分表或分區。mysql
二、MySQL分表
分表是將一個大表按照必定的規則分解成多張具備獨立存儲空間的實體表,每一個表都對應三個文件,MYD數據文件,.MYI索引文件,.frm表結構文件。這些表能夠分佈在同一塊磁盤上,也能夠在不一樣的機器上。app讀寫的時候根據事先定義好的規則獲得對應的表名,而後去操做它。
將單個數據庫表進行拆分,拆分紅多個數據表,而後用戶訪問的時候,根據必定的算法(如用hash的方式,也能夠用求餘(取模)的方式),讓用戶訪問不一樣的表,這樣數據分散到多個數據表中,減小了單個數據表的訪問壓力。提高了數據庫訪問性能。分表的目的就在於此,減少數據庫的負擔,縮短查詢時間。算法
Mysql分表分爲垂直切分和水平切分,具體區別以下:
垂直切分是指數據表列的拆分,把一張列比較多的表拆分爲多張表 一般咱們按如下原則進行垂直拆分: 把不經常使用的字段單獨放在一張表; 把text,blob(binary large object,二進制大對象)等大字段拆分出來放在附表中;
常常組合查詢的列放在一張表中; 垂直拆分更多時候就應該在數據表設計之初就執行的步驟,而後查詢的時候用join關鍵起來便可。sql
水平拆分是指數據錶行的拆分,把一張的表的數據拆成多張表來存放。 水平拆分原則,一般狀況下,咱們使用hash、取模等方式來進行表的拆分 好比一張有400W的用戶表users,爲提升其查詢效率咱們把其分紅4張表users1,users2,users3,users4 經過用ID取模的方法把數據分散到四張表內Id%4= [0,1,2,3] 而後查詢,更新,刪除也是經過取模的方法來查詢 部分業務邏輯也能夠經過地區,年份等字段來進行歸檔拆分; 進行拆分後的表,這時咱們就要約束用戶查詢行爲。好比咱們是按年來進行拆分的,這個時候在頁面設計上就約束用戶必需要先選擇年,而後才能進行查詢。
三、利用merge存儲引擎實現分表
注:只有myisam引擎的原表才能夠利用merge存儲引擎實現分表。數據庫
merge分表,分爲主表和子表,主表相似於一個殼子,邏輯上封裝了子表,實際上數據都是存儲在子表中的。 咱們能夠經過主表插入和查詢數據,若是清楚分表規律,也能夠直接操做子表。
例:
1)建立一個完整表app
mysql> create database test1; mysql> use test1; mysql> create table member -> ( -> id bigint auto_increment primary key, -> name varchar(20), -> sex tinyint not null default '0' -> )engine=myisam default charset=utf8 auto_increment=1; #插入數據 mysql> insert into member(name,sex) values('tom1',1); mysql> insert into member(name,sex) select name,sex from member; # 插入語句多執行幾回,便可插入大量的數據 mysql> select count(*) from member; # 手賤了,這裏我插入了16384條數據 +----------+ | count(*) | +----------+ | 16384 | +----------+ 1 row in set (0.00 sec)
2)對上面完整的表進行分表less
**分表注意事項:** * 子表和主表的字段定義須要一致,包括數據類型,數據長度等; * 當分表完成後,全部的操做(增刪改查)須要對主表進行,雖然主表並不存放實際的數據。
#建立兩個分表,表結構必須和上面完整的表結構一致 mysql> create table tb_member1 like member; mysql> create table tb_member2 like member; #建立merge引擎的表做爲主表,並關聯上面的兩個分表 mysql> create table tb_member -> ( -> id bigint auto_increment primary key, -> name varchar(20), -> sex tinyint not null default '0' -> )engine=merge union=(tb_member1,tb_member2) insert_method=last charset=utf8;
注:在上面建立主表時,指定的「insert_method=last」有三個可選參數,分別是:last:表示插入到最後一張表裏面;first:表示插入到第一張表裏面;NO:表示該表不能作任何寫入操做,只做爲查詢使用。
3)查看剛剛建立的三個表結構以下:
ide
4)將數據分到兩個表中:性能
mysql> insert into tb_member1(id,name,sex) select id,name,sex from member where id%2=0; Query OK, 8192 rows affected (0.01 sec) Records: 8192 Duplicates: 0 Warnings: 0 mysql> insert into tb_member2(id,name,sex) select id,name,sex from member where id%2=1; Query OK, 8192 rows affected (0.02 sec) Records: 8192 Duplicates: 0 Warnings: 0
5)查看主表和兩個子表中的數據
第一個子表部分數據以下:
第二個子表部分數據以下:
主表部分查詢的部分數據以下:
數據總行數以下:
注意:總表只是一個外殼,存取數據發生在一個一個的子表裏面。 每一個子表都有自已獨立的相關表文件,而主表只是一個殼,並無完整的相關表文件,當肯定主表中能夠查到的數據和分表以前查到的數據徹底一致時,就能夠將原來的表刪除了,以後對錶的讀寫操做,均可以對分表後的主表進行。
上面三個表對應的本地文件以下:
能夠看出,可以查詢到全部數據的主表的本地數據文件是很是小的,這也驗證了,數據並無存在這個主表中。
6)對主表進行插入數據的操做,以下:設計
mysql> insert into tb_member values(16385,'tom2',0),(16386,'tom3',1);
能夠看出,新增的兩條數據都插入在了第二張表中,由於在建立主表的時候,指定的「insert_method」是last,也就是全部插入數據的操做都是對最後一張表裏進行的,能夠經過alter指令修改插入方法,以下:code
mysql> alter table tb_member INSERT_METHOD=first;
修改插入方法後,再自行對錶進行插入數據的操做,能夠發現全部的數據都寫入了第一個表(我這裏插入了四條數據),查看以下:
mysql> insert into tb_member values(16387,'tom4',2),(16388,'tom5',3),(16389,'tom6',4),(16390,'tom7',5);
上面是新增了四條數據,能夠發現都插入到了第一張表。
若將插入方法修改成no,則表示這個表不能再插入任何數據,以下:
mysql> alter table tb_member insert_method=no; mysql> insert into tb_member values(16391,'tom7',9);
四、MySQL分區
1)什麼是分區?
分區和分表類似,都是按照規則分解表。不一樣在於分表將大表分解爲若干個獨立的實體表,而分區是將數據分段劃分在多個位置存放,分區後,表仍是一張表,但數據散列到多個位置了。app讀寫的時候操做的仍是表名字,db自動去組織分區的數據。
分區主要有如下兩種形式:
水平分區:這種形式分區是對錶的行進行分區,全部在表中定義的列在每一個數據集中都能找到,因此表的特性依然得以保持。
舉個簡單例子:一個包含十年發票記錄的表能夠被分區爲十個不一樣的分區,每一個分區包含的是其中一年的記錄。
垂直分區:這種分區方式通常來講是經過對錶的垂直劃分來減小目標表的寬度,使某些特定的列被劃分到特定的分區,每一個分區都包含了其中的列所對應的行。
舉個簡單例子:一個包含了大text和BLOB列的表,這些text和BLOB列又不常常被訪問,這時候就要把這些不常用的text和BLOB了劃分到另外一個分區,在保證它們數據相關性的同時還能提升訪問速度。
2)查看當前數據庫是否支持分區
MySQL 5.6以前,使用下面的參數查看當前配置是否支持分區(若是爲yes則表示支持分區):
mysql> SHOW VARIABLES LIKE '%partition%'; +-----------------------+---------------+ |Variable_name | Value | +-----------------------+---------------+ | have_partition_engine | YES | +-----------------------+------------------+
在5.6及之後採用如下方式查看:
mysql> show plugins;
返回的結果中,有如下字段(若是status列爲「ACTIVE」,則表示支持分區):
3)按照範圍(range)方式的表分區
mysql> create table user -> ( -> id int not null auto_increment, -> name varchar(30) not null default '', -> sex int(1) not null default '0', -> primary key(id) -> )default charset=utf8 auto_increment=1 -> partition by range(id) -> ( -> partition p0 values less than (3), -> partition p1 values less than (6), -> partition p2 values less than (9), -> partition p3 values less than (12), -> partition p4 values less than maxvalue -> );
注:在上面建立的表中,當id列的值小於3將會插入到p0分區,大於3小於6的記錄將會插入到p1分區,以此類推,全部id值大於12的記錄都會插入到p4分區。
4)利用存儲過程插入一些數據
mysql> delimiter // mysql> create procedure adduser() -> begin -> declare n int; -> declare summary int; -> set n = 0; -> while n <= 20 -> do -> insert into test1.user(name,sex) values("tom",0); -> set n=n+1; -> end while; -> end // Query OK, 0 rows affected (0.01 sec) mysql> delimiter ; mysql> delimiter ; mysql> call adduser(); Query OK, 1 row affected (0.01 sec) mysql> select * from user; +----+------+-----+ | id | name | sex | +----+------+-----+ | 1 | tom | 0 | | 2 | tom | 0 | | 3 | tom | 0 | | 4 | tom | 0 | | 5 | tom | 0 | | 6 | tom | 0 | | 7 | tom | 0 |
5)到存放數據表文件的目錄下看一下:
能夠看到數據是被分散存到不一樣的文件中的,本地的文件名都是「user#P#p0...」命名的,其中p0是自定義的分區名。
6)統計數據行數
mysql> select count(*) from user; +----------+ | count(*) | +----------+ | 21 | +----------+ 1 row in set (0.00 sec)
7)從information_schema系統庫中的partition表中查看分區信息
mysql> select * from information_schema.partitions where table_schema='test1' and table_name='user'\G
8)從分區中查詢數據
9)添加及合併分區(須要先合併分區再新增分區)
1.添加分區:
注意:因爲在建立表的時候,指定的最後一個分區range是maxvalue,因此是沒法直接增長分區的,以下:
mysql> alter table user add partition (partition p5 values less than (20)); ERROR 1481 (HY000): MAXVALUE can only be used in last partition definition
大意是:MAXVALUE只能在最後一個分區定義中使用
但也不能夠將最後定義了maxvalue的分區直接刪除,由於刪除分區的話,分區中的數據也會丟失,因此,若是須要新增分區的正確作法,應該是先合併分區,再新增分區,這樣才能夠保證數據的完整性,以下:
mysql> alter table user reorganize partition p4 into (partition p03 values less than (15),partition p04 values less than maxvalue );
上述命令的做用就是將最後一個分區分爲兩個分區,一個是本身所須要的分區,最後一個分區仍是maxvalue(也必須是maxvalue),這樣就完成了添加分區。
本地表文件以下:
查詢新增分區中的數據以下:
2.合併分區
將p0、p一、p二、p3四個分區合併爲p02:
mysql> alter table user reorganize partition p0,p1,p2,p3 into -> (partition p02 values less than (12));
能夠看到p02將整合了p0,p1,p2,p3三個分區的數據,以下:
本地文件以下:
10) 刪除分區
mysql> alter table user drop partition p02;
注意:分區被刪除後,分區中的數據也將被刪除,刪除分區p02的表中全部數據以下: