(3) MySQL分區表使用方法

1. 確認MySQL服務器是否支持分區表

命令:mysql

show plugins;

2. MySQL分區表的特色

  • 在邏輯上爲一個表,在物理上存儲在多個文件中

HASH分區(HASH)

HASH分區的特色

  • 根據MOD(分區鍵,分區數)的值把數據行存儲到表的不一樣分區中
  • 數據能夠平均的分佈在各個分區中
  • HASH分區的鍵值必須是一個INT類型的值,或是經過函數能夠轉爲INT類型

如何創建HASH分區表

以INT類型字段 customer_id爲分區鍵

CREATE TABLE `customer_login_log` (
  `customer_id` int(10) unsigned NOT NULL COMMENT '登陸用戶ID',
  `login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '用戶登陸時間',
  `login_ip` int(10) unsigned NOT NULL COMMENT '登陸IP',
  `login_type` tinyint(4) NOT NULL COMMENT '登陸類型:0未成功 1成功'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶登陸日誌表'

PARTITION BY HASH(customer_id)  PARTITIONS 4;

以非INT類型字段 login_time 爲分區鍵(須要先轉換成INT類型)

CREATE TABLE `customer_login_log` (
  `customer_id` int(10) unsigned NOT NULL COMMENT '登陸用戶ID',
  `login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '用戶登陸時間',
  `login_ip` int(10) unsigned NOT NULL COMMENT '登陸IP',
  `login_type` tinyint(4) NOT NULL COMMENT '登陸類型:0未成功 1成功'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶登陸日誌表'

PARTITION BY HASH(UNIX_TIMESTAMP(login_time))  PARTITIONS 4;

customer_login_log 表若是不分區,在物理磁盤上文件爲sql

customer_login_log.frm    # 存儲表原數據信息
customer_login_log.ibd    # Innodb數據文件

若是按上面的建HASH分區表,則有五個文件數據庫

customer_login_log.frm    
customer_login_log#P#p0.ibd
customer_login_log#P#p1.ibd
customer_login_log#P#p2.ibd
customer_login_log#P#p3.ibd

演示

使用起來和不分區是同樣的,看起來只有一個數據庫,其實有多個分區文件,好比咱們要插入一條數據,不須要指定分區,MySQL會自動幫咱們處理服務器

查詢函數

範圍分區(RANGE)

RANGE分區特色

  • 根據分區鍵值的範圍把數據行存儲到表的不一樣分區中
  • 多個分區的範圍要連續,可是不能重疊
  • 默認狀況下使用VALUES LESS THAN屬性,即每一個分區不包括指定的那個值

如何創建RANGE分區

若是沒有定義p3分區,當插入的customer_id大於29999時會報錯,定義了則超過的數據都存入p3中優化

RANGE分區的適用場景

  • 分區鍵爲日期或是時間類型 (可使得各個分區表的數據比較均衡,若是按上面的例子中以整型id爲分區鍵,假如活躍用戶集中在10000-19999之間,則p1中的數據量就會比其餘分區的數據量大不少,這就失去了分區的意義;並且按時間類型分區,若是要按時間順序進行數據的歸檔,則只須要對某一個分區進行歸檔就能夠了)
  • 全部查詢中都包括分區鍵(避免跨分區查詢)
  • 按期按分區範圍清理歷史數據

LIST分區

LIST分區的特色

  • 按分區鍵取值的列表進行分區
  • 同範圍分區同樣,各分區的列表值不能重複
  • 每一行數據必須能找到對應的分區列表,不然數據插入失敗

如何創建LIST分區

若是插入一條login_type爲10的數據行,則會報錯插件

3. 如何爲登陸日誌表(customer_login_log)分區

業務場景

  • 用戶每次登陸都會記錄customer_login_log日誌
  • 用戶登陸日誌保存一年,1年後能夠刪除或者歸檔

登陸日誌表的分區類型及分區鍵

  • 使用RANGE分區
  • 以login_time爲分區鍵

分區後的用戶登陸日誌表

按年份分區存儲,因此用YEAR函數進行了轉化3d

CREATE TABLE `customer_login_log` (
  `customer_id` int(10) unsigned NOT NULL COMMENT '登陸用戶ID',
  `login_time` DATETIME NOT NULL COMMENT '用戶登陸時間',
  `login_ip` int(10) unsigned NOT NULL COMMENT '登陸IP',
  `login_type` tinyint(4) NOT NULL COMMENT '登陸類型:0未成功 1成功'
) ENGINE=InnoDB 
PARTITION BY RANGE (YEAR(login_time))(
PARTITION p0 VALUES LESS THAN (2017),
PARTITION p1 VALUES LESS THAN (2018),
PARTITION p2 VALUES LESS THAN (2019)
)

插入並查詢數據日誌

查詢指定表中的分區數據狀況

SELECT table_name,partition_name,partition_description,table_rows FROM
information_schema.`PARTITIONS`  WHERE table_name = 'customer_login_log';

再插入2條18年的日誌,會存入p2表中code

以前說過創建分區表時,最好創建一個MAXVALUE的分區,這裏之因此沒有創建,是爲了數據維護的方便,若是咱們創建了MAXVALUE分區,很容易忽視一個問題,當咱們2019年有的數據插入時,會自動存入那個MAXVALUE分區中,以後在作數據維護時會不方便,因此沒有創建MAXVALUE分區
而是經過計劃任務的方式,在每一年年末的時候增長這個分區,好比咱們如今在2018年年末,咱們須要在日誌表中爲2019年創建日誌分區,不然2019年的日誌都會插入失敗

咱們能夠經過下面語句

增長分區

ALTER TABLE customer_login_log ADD PARTITION (PARTITION p3 VALUES LESS THAN(2020))

增長分區,並插入數據

刪除分區

假如咱們如今要刪除2016年到2017年間一年的數據,由於咱們已經作了分區,因此只須要經過一條語句,刪除p0分區便可

ALTER TABLE customer_login_log DROP PARTITION p0;

能夠發現p0分區已被刪除,且2016年的日誌所有被清除了

歸檔分區歷史數據

咱們可能有另外一種需求對數據進行歸檔

Mysql版本>=5.7,歸檔分區歷史數據很是方便,提供了一個交換分區的方法

分區數據歸檔遷移條件:

  1. MySQL>=5.7
  2. 結構相同
  3. 歸檔到的數據表必定要是非分區表
  4. 非臨時表;不能有外鍵約束
  5. 歸檔引擎要是:archive

建表並交換分區

CREATE TABLE `arch_customer_login_log` (
  `customer_id` INT unsigned NOT NULL COMMENT '登陸用戶ID',
  `login_time` DATETIME NOT NULL COMMENT '用戶登陸時間',
  `login_ip` INT unsigned NOT NULL COMMENT '登陸IP',
  `login_type` TINYINT NOT NULL COMMENT '登陸類型:0未成功 1成功'
) ENGINE=InnoDB ;

ALTER TABLE customer_login_log 
    exchange  PARTITION p1 WITH TABLE arch_customer_login_log;

能夠發現,原customer_login_log表中的2017年的數據(p1分區中的數據)已轉移到了arch_customer_login_log表中,可是p1分區未刪除,只是數據轉移了,因此咱們還須要執行DROP命令刪除分區,以避免有數據插入其中

將歸檔數據的存儲引擎改成歸檔引擎

最後咱們將歸檔數據的存儲引擎改成歸檔引擎,命令爲

ALTER TABLE customer_login_log  ENGINE=ARCHIVE;

使用歸檔引擎的好處是:它比Innodb所佔用的空間更少,可是歸檔引擎只能進行查詢操做,不能進行寫操做

4. 使用分區表的主要事項

  • 結合業務場景選擇分區鍵,避免跨分區查詢
  • 對分區表進行查詢最好在WHERE從句中包含分區鍵
  • 具備主鍵或惟一索引的表,主鍵或惟一索引必須是分區鍵的一部分(這也是爲何咱們上面分區時去掉了主鍵登陸日誌id(login_id)的緣由,否則就沒法按照上面的按年份進行分區,因此分區表其實更適合在MyISAM引擎中)

關於MyISAM和Innodb的索引區別

1.關於自動增加

myisam引擎的自動增加列必須是索引,若是是組合索引,自動增加能夠不是第一列,他能夠根據前面幾列進行排序後遞增。

innodb引擎的自動增加咧必須是索引,若是是組合索引也必須是組合索引的第一列。

2.關於主鍵

myisam容許沒有任何索引和主鍵的表存在,

myisam的索引都是保存行的地址。

innodb引擎若是沒有設定主鍵或者非空惟一索引,就會自動生成一個6字節的主鍵(用戶不可見)

innodb的數據是主索引的一部分,附加索引保存的是主索引的值。

3.關於count()函數

myisam保存有表的總行數,若是select count(*) from table;會直接取出出該值

innodb沒有保存表的總行數,若是使用select count(*) from table;就會遍歷整個表,消耗至關大,可是在加了wehre 條件後,myisam和innodb處理的方式都同樣。

4.全文索引

myisam支持 FULLTEXT類型的全文索引

innodb不支持FULLTEXT類型的全文索引,可是innodb可使用sphinx插件支持全文索引,而且效果更好。(sphinx 是一個開源軟件,提供多種語言的API接口,能夠優化mysql的各類查詢)

5.delete from table

使用這條命令時,innodb不會重新創建表,而是一條一條的刪除數據,在innodb上若是要清空保存有大量數據的表,最 好不要使用這個命令。(推薦使用truncate table,不過須要用戶有drop此表的權限)

6.索引保存位置

myisam的索引以表名+.MYI文件分別保存。

innodb的索引和數據一塊兒保存在表空間裏。

相關文章
相關標籤/搜索