1. 程式人生 > >Mysql資料庫表分割槽深入詳解

Mysql資料庫表分割槽深入詳解

0、mysql資料庫分割槽的由來?

1)傳統不分割槽資料庫痛點

mysql資料庫中的資料是以檔案的形勢存在磁碟上的,預設放在/mysql/data下面(可以通過my.cnf中的datadir來檢視),
一張表主要對應著三個檔案,一個是frm存放表結構的,一個是myd存放表資料的,一個是myi存表索引的。

[[email protected] test]# ls -al
總用量 1811444
drwx------ 2 mysql mysql 4096 10月 17 15:12 .
drwxr-xr-x 4 mysql mysql 4096 10月 17 14:37 ..
-rw-rw---- 1
mysql mysql 8962 1010 17:45 bz_info.frm
-rw-rw---- 1 mysql mysql 347727032 1017 15:16 bz_info.MYD -rw-rw---- 1 mysql mysql 56341504 1017 15:16 bz_info.MYI -rw-rw---- 1 mysql mysql 8962 1010 17:44 dz_info.frm -rw-rw---- 1 mysql mysql 418645764 1017 15:15 dz_info.MYD -rw-rw---- 1 mysql mysql 81381376
1017 15:15 dz_info.MYI

2)資料庫分割槽處理

如果一張表的資料量太大的話,那麼myd,myi就會變的很大,查詢資料就會變的很慢,這個時候我們可以利用mysql的分割槽功能,在物理上將這一張表對應的三個檔案,分割成許多個小塊,這樣呢,我們查詢一條資料時,就不用全部查找了,只要知道這條資料在哪一塊,然後在那一塊找就行了。如果表的資料太大,可能一個磁碟放不下,這個時候,我們可以把資料分配到不同的磁盤裡面去。

表分割槽是Mysql被Oracle收購後推出的一個新特性。

一、表分割槽通俗解釋

通俗地講表分割槽是將一大表,根據條件分割成若干個小表。mysql5.1開始支援資料表分割槽了。
如:某使用者表的記錄超過了600萬條,那麼就可以根據入庫日期將表分割槽,也可以根據所在地將表分割槽。當然也可根據其他的條件分割槽。

二、為什麼要對錶進行分割槽?

為了改善大型表以及具有各種訪問模式的表的可伸縮性,可管理性和提高資料庫效率。

2.1 表分割槽要解決的問題:

當表非常大,或者表中有大量的歷史記錄,而“熱資料”卻位於表的末尾。如日誌系統、新聞。。此時就可以考慮分割槽表。【注:此處也可以使用分表,但是會增加業務的複雜性。】

2.2 表分割槽有如下優點:

1)與單個磁碟或檔案系統分割槽相比,可以儲存更多的資料。
2)對於那些已經失去儲存意義的資料,通常可以通過刪除與那些資料有關的分割槽,很容易地刪除那些資料。
相反地,在某些情況下,新增新資料的過程又可以通過為那些新資料專門增加一個新的分割槽,來很方便地實現。
同樣的,你可以很快的通過刪除分割槽來移除舊資料。你還可以優化、檢查、修復個別分割槽。
3)一些查詢可以得到極大的優化。 可以把一些歸類的資料放在一個分割槽中,可以減少伺服器檢查資料的數量加快查詢。
這主要是藉助於滿足一個給定WHERE語句的資料可以只儲存在一個或多個分割槽內,這樣在查詢時就不用查詢其他剩餘的分割槽。
PS:因為分割槽可以在建立了分割槽表後進行修改,所以在第一次配置分割槽方案時還不曾這麼做時,可以重新組織資料,來提高那些常用查詢的效率。
4)涉及到例如SUM()和COUNT()這樣聚合函式的查詢,可以很容易地進行並行處理。
這種查詢的一個簡單例子如
“SELECT salesperson_id, COUNT (orders) as order_total FROM sales GROUP BY salesperson_id;”。
通過“並行”,這意味著該查詢可以在每個分割槽上同時進行,最終結果只需通過總計所有分割槽得到的結果。
5)通過跨多個磁碟來分散資料查詢,來獲得更大的查詢吞吐量。

三、mysql分割槽型別

根據所使用的不同分割槽規則可以分成幾大分割槽型別。
這裡寫圖片描述

3.1 RANGE 分割槽:

基於屬於一個給定連續區間的列值,把多行分配給分割槽。
舉例:

create table foo_range (
id int not null auto_increment,
created DATETIME,
primary key (id, created)
) engine = innodb partition by range (TO_DAYS(created))(
PARTITION foo_1 VALUES LESS THAN (TO_DAYS('2016-10-18')),
PARTITION foo_2 VALUES LESS THAN (TO_DAYS('2017-01-01'))
);

//新增一個分割槽
ALTER TABLE foo_range ADD PARTITION(
PARTITION foo_3 VALUES LESS THAN (TO_DAYS('2017-10-18'))
);

//插入資料
insert into `foo_range` (`id`, `created`) values (1, '2016-10-17'),(2, '2016-10-20'),(3, '2016-1-25');

//查詢
explain partitions select * from foo_range where created = '2016-10-20';

//查詢結果:
mysql> explain partitions select * from foo_range where created = '2016-10-20';
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+--------------------------+
| 1 | SIMPLE | foo_range | foo_2 | index | NULL | PRIMARY | 12 | NULL | 2 | Using where; Using index |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+--------------------------+

3.2 LIST 分割槽:

類似於按RANGE分割槽,區別在於LIST分割槽是基於列值匹配一個離散值集合中的某個值來進行選擇。

create table foo_list
(empno varchar(20) not null ,
empname varchar(20),
deptno int,
birthdate date not null,
salary int
)
partition by list(deptno)
(
partition p1 values in (10),
partition p2 values in (20),
partition p3 values in (30)
);

以上顯示,以部門號為分割槽依據,每個部門一個分割槽。

3.3 HASH分割槽:

基於使用者定義的表示式的返回值來進行選擇的分割槽,該表示式使用將要插入到表中的這些行的列值進行計算。這個函式可以包含MySQL中有效的、產生非負整數值的任何表示式。
HASH分割槽主要用來確保資料在預先確定數目的分割槽中平均分佈。在RANGE和LIST分割槽中,必須明確指定一個給定的列值或列值集合應該儲存在哪個分割槽中。
在HASH分割槽中,MySQL 自動完成這些工作,你所要做的只是基於將要被雜湊的列值指定一個列值或表示式,以及指定被分割槽的表將要被分割成的分割槽數量。

create table foo_hash
(empno varchar(20) not null ,
empname varchar(20),
deptno int,
birthdate date not null,
salary int
)
partition by hash(year(birthdate))
partitions 4;

以上建立了4個分割槽。

3.4 KEY分割槽:

類似於按HASH分割槽,區別在於KEY分割槽只支援計算一列或多列,且MySQL伺服器提供其自身的雜湊函式。必須有一列或多列包含整數值。

create table foo_key

(empno varchar(20) not null ,

empname varchar(20),

deptno int,

birthdate date not null,

salary int

)

partition by key(birthdate)

partitions 4;

3.5 複合分割槽:

基於RANGE/LIST 型別的分割槽表中每個分割槽的再次分割。子分割槽可以是 HASH/KEY 等型別。

四、常見分割槽操作

這裡寫圖片描述

修改已有表舉例:

ALTER TABLE bj_info
PARTITION BY RANGE(id) PARTITIONS 14(
PARTITION part_00yntai VALUES LESS THAN (610001),
PARTITION part_01shxia VALUES LESS THAN (1220001),
PARTITION part_02zhfu VALUES LESS THAN (1830001),
PARTITION part_03fuhan VALUES LESS THAN (2440001),
PARTITION part_04mping VALUES LESS THAN (3660001),
PARTITION part_06chngdao VALUES LESS THAN (4270001),
PARTITION part_07lonkou VALUES LESS THAN (4880001),
PARTITION part_08layang VALUES LESS THAN (5490001),
PARTITION part_09laihou VALUES LESS THAN (6100001),
PARTITION part_10peglai VALUES LESS THAN (6710001),
PARTITION part_11zhoyuan VALUES LESS THAN (7320001),
PARTITION part_12qixa VALUES LESS THAN (7930001),
PARTITION part_13haiyng VALUES LESS THAN (8540000),
PARTITION part_05laisan VALUES LESS THAN MAXVALUE
);

五、獲取分割槽表資訊的方法

5.1 show create table 表名

可以檢視建立分割槽表的create語句
舉例:

mysql> show create table foo_list;
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| foo_list | CREATE TABLE `foo_list` (
  `empno` varchar(20) NOT NULL,
  `empname` varchar(20) DEFAULT NULL,
  `deptno` int(11) DEFAULT NULL,
  `birthdate` date NOT NULL,
  `salary` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
/*!50100 PARTITION BY LIST (deptno)
(PARTITION p1 VALUES IN (10) ENGINE = MyISAM,
 PARTITION p2 VALUES IN (20) ENGINE = MyISAM,
 PARTITION p3 VALUES IN (30) ENGINE = MyISAM) */ |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

5. 2 show table status

可以查看錶是不是分割槽表
舉例:
SHOW TABLE STATUS LIKE ‘foo_range’;
結果如紅色部分所示:
這裡寫圖片描述

5.3 檢視information_schema.partitions表

如下命令可以查看錶具有哪幾個分割槽、分割槽的方法、分割槽中資料的記錄數等資訊

mysql> select
  -> partition_name part,
  -> partition_expression expr,
  -> partition_description descr,
  -> table_rows
  -> from information_schema.partitions where
  -> table_schema = schema()
  -> and table_name='foo_range';
+-------+------------------+--------+------------+
| part | expr | descr | table_rows |
+-------+------------------+--------+------------+
| foo_1 | TO_DAYS(created) | 736620 | 2 |
| foo_2 | TO_DAYS(created) | 736695 | 1 |
| foo_3 | TO_DAYS(created) | 736985 | 0 |
+-------+------------------+--------+------------+
3 rows in set (0.00 sec)

5.4 explain partitions select語句

通過此語句來顯示掃描哪些分割槽,及他們是如何使用的.
舉例如下:

mysql> explain partitions select * from foo_range;
+----+-------------+-----------+-------------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | foo_range | foo_1,foo_2,foo_3 | index | NULL | PRIMARY | 12 | NULL | 4 | Using index |
+----+-------------+-----------+-------------------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)

六、效能對比(分割槽表和非分割槽表)

步驟一:建立兩張表: part_tab(分割槽表),no_part_tab(普通表)

CREATE TABLE part_tab
(c1 int default NULL, c2 varchar(30) default NULL, c3 date not null)
 PARTITION BY RANGE(year(c3))
(PARTITION p0 VALUES LESS THAN (1995),
PARTITION p1 VALUES LESS THAN (1996) ,
PARTITION p2 VALUES LESS THAN (1997) ,
PARTITION p3 VALUES LESS THAN (1998) ,
PARTITION p4 VALUES LESS THAN (1999) ,
PARTITION p5 VALUES LESS THAN (2000) ,
PARTITION p6 VALUES LESS THAN (2001) ,
PARTITION p7 VALUES LESS THAN (2002) ,
PARTITION p8 VALUES LESS THAN (2003) ,
PARTITION p9 VALUES LESS THAN (2004) ,
PARTITION p10 VALUES LESS THAN (2010),
PARTITION p11 VALUES LESS THAN (MAXVALUE) );

CREATE TABLE no_part_tab(c1 int default NULL, c2 varchar(30) default NULL, c3 date not null);

步驟二:建立儲存過程。

CREATE PROCEDURE load_part_tab()
  begin
  declare v int default 0;
  while v < 8000000
  do
  insert into part_tab
  values (v,'testingpartitions',adddate('1995-01-01',(rand(v)*36520)mod 3652));
  set v = v + 1;
  end while;
end;

//呼叫儲存過程,插入資料
call load_part_tab();

//從 part_tab 匯入資料到 no_part_tab

insert into no_part_tab select * from part_tab;

步驟三:執行查詢速度比對

select count(*) from part_tab where c3 > date '1995-01-01' and c3 < date '1995-12-31';

耗時:0.407s

select count(*) from no_part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';

耗時:3.716s:3.716/0.407=9.13倍。

掃描次數對比:

mysql> explain select count(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | part_tab | ALL | NULL | NULL | NULL | NULL | 798458 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

mysql> explain select count(*) from no_part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31';
+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | no_part_tab | ALL | NULL | NULL | NULL | NULL | 8000000 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

如上:普通表掃描了 8000000次, 分割槽表掃描了798458次。
分割槽表掃描比例是普通表的:798458/ 8000000 = 9.98%。

七、分割槽適用場景

7.1常見使用場景

1)當資料量很大(過T)時,肯定不能把資料再如到記憶體中,這樣查詢一個或一定範圍的item是很耗時。另外一般這情況下,歷史資料或不常訪問的資料佔很大部分,最新或熱點資料佔的比例不是很大。這時可以根據有些條件進行表分割槽。

2)分割槽表的更易管理,比如刪除過去某一時間的歷史資料,直接執行truncate,或者狠點drop整個分割槽,這比detele刪除效率更高

3)當資料量很大,或者將來很大的,但單塊磁碟的容量不夠,或者想提升IO效率的時候,可以把沒分割槽中的子分割槽掛載到不同的磁碟上。

4)使用分割槽表可避免某些特殊的瓶頸,例如Innodb的單個索引的互斥訪問..

5)單個分割槽表的備份很恢復會更有效率,在某些場景下

總結:可伸縮性,可管理性,提高資料庫查詢效率。

7.2 業務場景舉例

專案中需要動態新建、刪除分割槽。如新聞表,按照時間維度中的月份對其分割槽,為了防止新聞表過大,只保留最近6個月的分割槽,同時預建後面3個月的分割槽,這個刪除、預建分割槽的過程就是分割槽表的動態管理。

2016年10月21日 20:52 思於家中床前

相關推薦

Mysql資料庫分割槽深入

0、mysql資料庫分割槽的由來? 1)傳統不分割槽資料庫痛點 mysql資料庫中的資料是以檔案的形勢存在磁碟上的,預設放在/mysql/data下面(可以通過my.cnf中的datadir來檢視), 一張表主要對應著三個檔案,一個是frm存放表結構的

mysql 資料庫my.cnf配置

[client] port = 3306 socket = /data/3306/mysql.sock [mysql] prompt="\[email protected] \R:\m:\s [\d]>" no-auto-rehash [mysqld] u

MySQL資料庫的字串型別(01)

Mysql的資料型別主要分為三類:數字型別、字串(字元)型別、日期和時間型別,由於時間緊迫,根據學習的需要 數字型別暫不做詳解,等待有時間了在修改此文件,此文主要介紹mysql 資料型別中的字串型別; 注:資料型別支援附加引數,例如:float(7,3),7代表顯示的數值

elasticsearch-jdbc實現MySQL同步到ElasticSearch深入

                     1.如何實現mysql與elasticsearch的資料同步?逐條轉換為json顯然不合適,需要藉助第三方工具或者自己實現。核心功能點:同步增、刪、改、查同步。2、mysql與elasticsearch同步的方法有哪些?優缺點對比?目前該領域比較牛的外掛有:1-3同步

SQL資料庫連線圖文

總結:left join 以左表為準,查詢出左表的所有資料,右表中有對應的則顯示出來,沒有對應的則顯示為null.注:A left join B on  與  A,B where  有相同效果,如下:select student.* ,Score.* from student inner join Score

win7-MySQL資料庫安裝與配置

目錄 一、概述 一、概述   MySQL版本:5.7.17   客戶端工具:NavicatforMySQL  二、MySQL安裝  安裝條件:   如果Windows Server 2003 在安裝.net framework4.0安裝過程中報錯: net framework 4.0安裝時提

MySQL分割槽

一、什麼是表分割槽 通俗地講表分割槽是將一大表,根據條件分割成若干個小表。mysql5.1開始支援資料表分割槽了。 如:某使用者表的記錄超過了600萬條,那麼就可以根據入庫日期將表分割槽,也可以根據所在地將表分割槽。當然也可根據其他的條件分割槽。二、為什麼要對錶進行分割槽 為了改善大型表以及具有各種訪問

MYSQL資料庫之----的操作

此篇主要介紹資料庫中表的操作。資料庫是表的容器,表,必須輸入某個資料庫,因此在建立表之前要指明資料庫。1.表的建立列定義: 列名   列的資料型別   [列的屬性(約束)]建立表的SQL命令:create table 表名(列結構) [表選項];查看錶的定義,可以用DESCR

MySql結構修改

參數 詳解 增加 not des reat fault sign charset 修改表的語法=========================增加列[add 列名]=========================①alter table 表名 add 列名 列類型 列參

mysql分區

sql char 根據 blank 服務端 lpad one urn 聯系 為什麽要分表和分區? 日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,導致數據庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性

MySQL(九)之數據的查詢(SELECT語法)二

clas reg 3.2 查詢語句 我們 lin where 過濾 情況 上一篇講了比較簡單的單表查詢以及MySQL的組函數,這一篇給大家分享一點比較難得知識了,關於多表查詢,子查詢,左連接,外連接等等。希望大家能都得到幫助! 在開始之前因為要多表查詢,所以搭建好環境:

MySQL約束條件和多查詢方式

left join 思考 mar 提高 詳解 union 存儲 class mys 一、約束什麽是約束?簡述:除了數據類型以外的約束的為什麽使用約束?簡述:為了保證數據的合法性 完整性;二、約束分類:  not null 跟整型時使用其作用是限制插入數據不能為空 crea

關係型資料庫掃描分片

導讀:資料匯流排(DBus)專注於資料的實時採集與實時分發,可以對IT系統在業務流程中產生的資料進行匯聚,經過轉換處理後成為統一JSON的資料格式(UMS),提供給不同資料使用方訂閱和消費,充當數倉平臺、大資料分析平臺、實時報表和實時營銷等業務的資料來源。在上一篇關於DBus的文章中,我們主要介紹了在DBus

SELECT INTO 和 INSERT INTO SELECT 兩種複製語句(SQL資料庫和Oracle資料庫的區別)

https://www.cnblogs.com/mq0036/p/4155136.html 我們經常會遇到需要表複製的情況,如將一個table1的資料的部分欄位複製到table2中,或者將整個table1複製到table2中,這時候我們就要使用SELECT INTO 和 INSER

c++使用Accesss資料庫操作Excel(CRecordset類)

目錄 1.      動態集、快照、游標和游標庫 2.      域資料成員與資料交換 3.      SQL查詢 4. &

logstash-input-jdbc實現mysql 與elasticsearch實時同步深入

引言: elasticsearch 的出現使得我們的儲存、檢索資料更快捷、方便。但很多情況下,我們的需求是:現在的資料儲存在mysql、oracle等關係型傳統資料庫中,如何儘量不改變原有資料庫表結構,將這些資料的insert,update,delete操作結果實時同步到elasticsearch(

PHP-Mysql 聯合做分分庫操作

一、當Mysql資料量過大時,就會面臨壓力分解,這時分庫分表是一個不錯的解決方案,現在我們就來談談Mysql如何分庫分表比較理想,然後再用php如何呼叫。 1,主從複製,讀寫分離 對主庫修改資料,

MySQL(九)之資料的查詢(SELECT語法)二

上一篇講了比較簡單的單表查詢以及MySQL的組函式,這一篇給大家分享一點比較難得知識了,關於多表查詢,子查詢,左連線,外連線等等。希望大家能都得到幫助! 在開始之前因為要多表查詢,所以搭建好環境:   1)建立資料表suppliers   前面已經有一張表是book表,我們

深入理解Oracle(5):三大連線方式之Hash Join的定義,原理,演算法,成本,模式和點陣圖

 Hash Join只能用於相等連線,且只能在CBO優化器模式下。相對於nested loop join,hash join更適合處理大型結果集        Hash Join的執行計劃第1個是hash表(build table),第2個探查表(probe table),

go-mysql-elasticsearch實現mysql 與elasticsearch實時同步深入

引言: go-mysql-elasticsearch 是國內作者開發的一款外掛。測試表明:該外掛優點:能實現同步增、刪、改、查操作。不足之處(待完善的地方): 1、仍處理開發、相對不穩定階段; 2、沒有日誌,不便於排查問題及檢視同步結果。 本文深入詳解了