日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql技术分享--表分区实现

發布時間:2023/12/4 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql技术分享--表分区实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

分區表

分區概念
  • 分區功能并不是在存儲引擎層完成的,因此不止有InnoDB存儲引擎支持分區,常見的存儲引擎MyISAM,NDB等都支持。但是也并不是所有存儲引擎都支持,比如CSV,FEDERATED,MERGE等就不支持,在使用分區功能之前應該先了解選擇的存儲引擎是否支持分區操作。
  • MySQL是在5.1版本之后添加了對于分區的支持。功能是將表或者索引分解成更小的多個,更可管理的部分。就訪問數據庫的應用而言,邏輯上還是一個表或者一個索引,但是物理上這個表或者索引可能由數十個物理分區組成,每個分區都是獨立的對象,可以獨立出來,也可以作為一個更大的對象的一部分進行處理。
  • MySQL數據庫支持的分區類型是水平分區(指同一個表中不同行的記錄分配到不同的物理文件),不支持垂直分區(指將同一個表中不同的列分配到不同的物理文件)
  • MySQL數據庫的分區是局部分區索引,一個分區中即存放了數據又存放了索引。
  • 如下命令查看是否開啟分區功能:
show variables like '%partition%'show plugins;

分區功能
  • 我們分區的作用一般是為了讓數據庫變得更快,但是啟用分區后,并不一定會變快。通過經驗來看分區對某些SQL語句的性能會帶來提高,但是分區主要用于高可用,更利于數據庫的管理。
  • 在OLTP應用中,對于分區的使用應該更小心。因為OLTP類型的數據庫對性能要求特別高,也行,分表分區能夠對某一批查詢效率提升,但是可能對其他某些查詢是致命的,導致他需要遍歷N個庫的全量數據,大大增加了IO次數。
  • 先了解當前MySQL數據庫支持的以下幾種類型的分區:
  • RANGE分區:行數據基于屬于一個給定連續區間的值放入分區。MySQL數據庫5.5開始支持RANGE COLUMNS的分區
  • LIST分區:和RANGE分區類似,只是LIST分區面向的是離散的值。同樣5.5開始支持LIST COLUMNS的分區
  • HASH分區:根據用戶自定義的表達式的返回值來進行分區,返回值不能為負數。
  • KEY分區:更具MySQL數據庫提供的哈希函數進行分區
錯誤案例
  • 注意,不論任何類型分區,如果表中存在主鍵或者唯一索引時候,分區必須是唯一索引的一個組成部分,因此如下案例會報錯:
create table t1( coll1 int not null, coll2 date not null, coll3 int not null, coll4 int not null, UNIQUE key(coll1, coll2) ) PARTITION by Hash(coll3) PARTITIONS 4;[Err] 1503 - A PRIMARY KEY must include all columns in the table's partitioning function
  • 將PARTITION by Hash(coll3) 修改成PARTITION by Hash(coll1)或者coll2 就能正確創建
唯一索引情況
  • 唯一索引可以允許是NULL值的,并且分區列只要是唯一索引的一個組成部分,不需要整個唯一索引列都是分區列
create table t1( coll1 int null, coll2 date null, coll3 int null, coll4 int null, UNIQUE key(coll1, coll2,coll3, coll4) ) PARTITION by Hash(coll3) PARTITIONS 4;
沒有主鍵或唯一索引情況
  • 當建表時沒有指定主鍵,唯一索引,可以指定任何一個列為分區列,如下兩種情況都可以正確創建案例:
create table t1( coll1 int not null, coll2 date not null, coll3 int not null, coll4 int not null ) PARTITION by Hash(coll3) PARTITIONS 4; create table t1( coll1 int not null, coll2 date not null, coll3 int not null, coll4 int not null, key (coll4) ) PARTITION by Hash(coll3) PARTITIONS 4;
RANGE分區
  • RANGE分區是常用的一種分區類型。如下案例,我們create table語句創建了一個id列的區間分區表。當id小于10 時候,數據插入P0分區。當大于等于10 小于等于20 插入p1:
create table t( id int )ENGINE=INNODB PARTITION by RANGE(id)( PARTITION p0 VALUES less than(10), PARTITION p1 VALUES less than(20) ); insert into t values(9),(10),(15)
  • 插入數據后,因為t根據id進行分區,因此數據是根據id列的值的范圍存放在不同的物理文件中,可以通過查information_schema 架構在的 PARTITIONS 表來查看每個分區的具體信息,在數據庫中有一個 information_schema數據庫
select * from information_schema.PARTITIONS where TABLE_SCHEMA=DATABASE() and TABLE_NAME = 't';

  • TABLE_ROWS列說明了每個分區記錄中記錄的數量,由于之前項表中插入了9,10,15三條記錄,因此可以看到,當前分區P0有一條記錄,分區p1 有2條記錄,PARTITION_METHOD 標識分區的類型,這里顯示的是RANGE
  • 對于表t,因為我們定義了分區,因此對于插入的值都嚴格遵循分區的定義,當插入不屬于分區的數據時候,會拋出異常:
[SQL] insert INTO t select 30; [Err] 1526 - Table has no partition for value 30
  • 應該添加新的范圍,使得數據庫分區能夠兼容所有的數據清空,如下:
alter table t add PARTITION(PARTITION p2 values less than MAXVALUE); insert INTO t select 30;
RANGE日期分區
  • RANGE分區主要用于日期列的分區,如對于銷售類的表,可以根據年份來分區存儲銷售數據,如下案例:
create table sales( money int UNSIGNED not null, date datetime )ENGINE=INNODB PARTITION by range(YEAR(date))( PARTITION p2008 values less than(2009), PARTITION p2009 values less than(2010), PARTITION p2010 values less than(2011) ); insert into sales values(100, '2008-01-01'), (100, '2008-02-01'), (200, '2008-01-02'), (100, '2009-03-01'), (200, '2010-03-01')select * from information_schema.PARTITIONS where TABLE_SCHEMA=DATABASE() and TABLE_NAME = 'sales';

  • 如上創建好,可以對sales這張表按時間處理賬本,如果我們需要刪除18年的數據,就不需要去delete from sales where date >=‘2008-01-01’ and date < ‘2009-01-01’ ,我們可以直接刪掉p2008分區即可,如下操作
alter table sales drop PARTITION p2008;

  • 分區操作還有另外一個好處,可以加快某些查詢的操作,如果我們只需要查詢19年的銷售額,如下:
EXPLAIN partitions select * from sales where date >='2009-01-01' and date < '2009-12-31'

  • 如上通過explain partitions 命令,上述語句sql優化器只需要搜索p2009分區,不用去全表掃描數據,大大提高執行速度,但是如上語句則不同:
EXPLAIN partitions select * from sales where date >='2009-01-01' and date < '2020-01-01'

  • 條件修改成了< 2020-01-01,這個時候優化器選擇p2009,p2010兩個分區,這是不希望看到的。因此對于啟用分區應該更具分區的特點編寫sql語句

  • 如果我們需要更細分,按月來分區,如下分區方式第查詢來說是無效的,如下:

create table sales( money int UNSIGNED not null, date datetime )ENGINE=INNODB PARTITION by range(YEAR(date)*100+MONTH(date))( PARTITION p201001 values less than(201002), PARTITION p201002 values less than(201003), PARTITION p201003 values less than(201004) ); insert into sales values(100, '2008-01-01'), (100, '2008-02-01'), (200, '2008-01-02'), (100, '2009-03-01'), (200, '2010-03-01')EXPLAIN partitions select * from sales where date >='2010-01-01' and date < '2010-01-31'

  • 如上查詢語句掃描的全分區,但是之前的邏輯應該只掃p2020001分區,這個問題原因在于RANGE分區的查詢,優化器只能對YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()這類函數進行優化選擇,因此對于上述要求,需要將分區函數改為TO_DAY,如下:
create table sales( money int UNSIGNED not null, date datetime )ENGINE=INNODB PARTITION by range(TO_DAYS(date))( PARTITION p201001 values less than(TO_DAYS('2010-02-01')), PARTITION p201002 values less than(TO_DAYS('2010-03-01')), PARTITION p201003 values less than(TO_DAYS('2010-04-01')) );EXPLAIN partitions select * from sales where date >='2010-01-01' and date < '2010-01-31'

  • 此時查詢只對p201001 分區進行掃描

LIST分區

  • LIST分區和RANGE分區類似,只是分區列的值是離散的,不連續,如下:
create table t( a int, b int )engine=INNODB PARTITION by list(b)( PARTITION p0 values in (1,3,5,7,9), PARTITION p1 values in (0,2,4,6,8) );insert into t values(1,1), (1,2), (1,3), (1,4)select * from information_schema.PARTITIONS where TABLE_SCHEMA=DATABASE() and TABLE_NAME = 't';

  • 如上,按奇數偶數分區,如果插入的值不值分區的定義,MySQL會拋出異常:
[SQL]insert into t values(1,100)[Err] 1526 - Table has no partition for value 100
  • 而且List有一個特殊地方,在insert插入多行時候,遇到未分區定義的值時候,MyISAM和InnoDB存儲引擎的處理完全不同,MyISAM會將之前的行都insert,之后的不成功,InnoDB存儲引擎會將他看成是一個事務,因此都會失敗,
[SQL]insert into t values(1,1), (1,2), (1,3), (1,4), (1,100)[Err] 1526 - Table has no partition for value 100
  • 如上是InnoDB存儲引擎,返回的是沒有對應的分區值,并且數據全失敗,
create table t( a int, b int )engine=MyISAM PARTITION by list(b)( PARTITION p0 values in (1,3,5,7,9), PARTITION p1 values in (0,2,4,6,8) ); insert into t values(1,1), (1,2), (1,3), (1,4), (1,100) select * from information_schema.PARTITIONS where TABLE_SCHEMA=DATABASE() and TABLE_NAME = 't';

  • 可以看到,插入的1,10,記錄是沒有成功的,之前的2,3,4都是已經成功insert。

HASH分區

  • HASH分區目的是將數據均由的分布的預定的各個分區中,保證個分區的數據大致一樣。在RANGE和LIST分區中,必須明確知道一個列值或者列值的集合。而在HASH分區中MySQL自動完成了這些工作,你需要做的是基于要被hash的列值指定一個列值或者表達式,以及指定備份區的表要被分割的分區數量,如下案例
create table t_hash( a int, b datetime )ENGINE=INNODB PARTITION by hash(YEAR(b)) PARTITIONS 4;
  • 如上hash規則,如果b列的值2010-04-01,那么這個記錄在t_hash中,保存的確認值如下
MOD(YEAR('2010-04-01'), 4)= MOD(2010,4) = 2
  • 如上計算,應該放到2分區中,
insert into t_hash values (1, '2010-04-01')select * from information_schema.PARTITIONS where TABLE_SCHEMA=DATABASE() and TABLE_NAME = 't_hash';

  • 如上數據落在了P2分區
  • MySQL數據庫還支持一種LINEAR HASH的分區,更負責的分區算法,
create table t_hash( a int, b datetime )ENGINE=INNODB PARTITION by LINEAR HASH (YEAR(b)) PARTITIONS 4;
  • MySQL數據庫用一下方式判斷分區
    • 取大于分區數量4 的下一個2 的冪值V, V = POWRE(2, CEILING(LOG(2,num))) = 4
    • 所在分區N= YEAR(‘2010-04-01’) & (V-1) = 2
  • 得到的分區還是2,但是HASH算法與之前的完全不同,
  • LINEAR HASH分區的有點在于,增加,刪除,合并和拆分分區變得更加快速,這有利于處理含有大量數據的表,缺點在于與使用HASH分區得到的數據分布相比,各個分區數據的分布不均勻。

KEY分區

上一篇:mysql技術分享-- 視圖是什么

總結

以上是生活随笔為你收集整理的mysql技术分享--表分区实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。