mysql面試

Mysql基礎篇--分區類型 原創: 潔癖汪 潔癖是一隻狗 昨天 分區是按照必定規則把一個表分解成多個更小的表,更容易管理的部分,當訪問數據庫應用而言,邏輯上是一個表或一個索引,其實是能夠有數個物理對象組成,每一個分區都是一個獨立的對象,能夠獨自處理做爲表的一部分進行數據處理java

分區的優勢node

和單個磁盤或文件相比,能夠儲存更多數據python

優化查詢,當where子句中包含分區條件的時候,能夠掃描一個或幾個分區提升查詢條件,同時處理sum() ,count()聚合函數的查詢能夠容易在每一個分區進行處理,最後彙總獲得結果mysql

對於不用的數據即將過時的數據,能夠刪除有關數據的某個分區nginx

多個磁盤分散數據的查詢,得到更大的查詢的吞吐量web

mysql 分區類型面試

RANGE分區:基於一個給定連續區間分爲,把數據分配到不通風分區 LIST :和RANGE相似,是基於給定枚舉值,把數據分配到不一樣的分區 HASH:基於分區的個數,把數據分配到不一樣的分區 KEY:和HASH相似 不管哪一種分區類型,要麼分區表不包含主鍵或惟一鍵,要麼分區表的主鍵或惟一鍵包含分區鍵,而且分區的名稱是區分大小寫的redis

RANGE分區spring

按照range分區表示利用取值範圍將數據分紅分區,區間要連續且不能重疊,使用values less than 進行分區定義,以下 mysql> create table emp( -> id int not null, -> name varchar(10), -> store_id int not null -> ) -> partition by range (store_id)( -> partition p0 values less than (10), -> partition p1 values less than (20), -> partition p2 values less than (30) -> ); Query OK, 0 rows affected (0.07 sec) mysql> insert into emp values (1,'jiepi',1),(2,'jiepi2',2),(3,'jiepi3',3); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 咱們把1-9存儲到p0分區,10-19存儲到p1,一次類推,可是當store_id大於30的時候會發生什麼呢?sql

mysql> insert into emp values (50,'jiepi50',50); ERROR 1526 (HY000): Table has no partition for value 50 咱們發現他是報錯的,所以我可使用values less than maxvalue語句添加分區,maxvalue 表明的是最大的可能的整數值,當服務器不知道把數據放到哪一個分區的時候,咱們就把這個數據放到這個分區。

mysql> alter table emp add partition (partition p3 values less than maxvalue); Query OK, 0 rows affected (0.08 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> insert into emp values (50,'jiepi50',50); Query OK, 1 row affected (0.01 sec) 分區使用的場景 當須要刪除過時的數據,只要簡單的執行 alter table emp drop partition po來刪除p0中的數據,對於上百萬的記錄表來講,刪除一個分區的數據,每每比使用delete 有效的多.

常常運行包含分區鍵的查詢,mysql能夠快速的明確只有某一個或者某些分區須要掃面,由於並非全部分區都要相關的數據,例如咱們要查詢store_id大於等25的數據,可能只要掃描p2分區。

LIST分區 list分區創建在離散的值列表告訴數據庫應該放到個分區,list分區不少方面是和range分區類似,區別在於list分區從屬於一個枚舉列表的值的集合,range是一個連續區間的集合,

list分區使用 partition by list(expr) 實現,expr 是某列值,或一個基於某列值得表達式,而後經過 values in (value_list) 方式定義分區,始終value_list是用逗號分隔的整數列表,他也沒必要按照上面順序聲明。 mysql> create table expenses( -> id int not null, -> category int, -> amout decimal (10,3) -> )partition by list (category) ( -> partition p0 values in (3,5), -> partition p1 values in (1,10), -> partition p2 values in (4,9), -> partition p3 values in (2), -> partition p4 values in (6) -> ); Query OK, 0 rows affected (0.15 sec)

mysql> insert into expenses values (1,1,12.9),(2,2,12.8); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 注意的是list分區沒有像range分區有values less than maxvalue,若是數據在list分區中不到會報錯,因此定分區的時候必須包含多有可能的值。

mysql> insert into expenses values (1,11,12.9),(2,2,12.8); ERROR 1526 (HY000): Table has no partition for value 11 columns分區

Columns分區是在mysql5.5引進的分區類型,上面的分區是都是基於整形分區,是爲了解決以前版本要進行函數或者表達式轉換成整形,他分爲 list columns 和 range columns ,他們支持 整形 日期 ,字符串,

整形:tinyint smallint ,mediumint ,int ,bigint ,其餘類型不支持

日期:data ,datatime

字符串:char ,varcahr ,binary ,varbinary 不支持 text和blob 類型作分區鍵

除了添加了類型支持,而且還支持多列分區. mysql> CREATE TABLE m_num( -> a INT, -> b INT -> ) -> PARTITION BY RANGE COLUMNS(a,b)( -> PARTITION p0 VALUES LESS THAN (0,10), -> PARTITION p1 VALUES LESS THAN (10,20), -> PARTITION p2 VALUES LESS THAN (10,MAXVALUE), -> PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE) -> ); Query OK, 0 rows affected (0.16 sec) 他的分區規則優勢稍微不同,他是按照字段組的比較

mysql> insert into m_num values (1,10); Query OK, 1 row affected (0.01 sec)

mysql> select (1,10)<(10,10) from m_num; +----------------+ | (1,10)<(10,10) | +----------------+ | 1 | +----------------+ 1 row in set (0.00 sec) mysql> select -> partition_name part , -> partition_expression expr, -> partition_description descr, -> table_rows -> from -> information_schema.partitions -> where table_schema=schema() -> and table_name='m_num'; +------+---------+-------------------+------------+ | part | expr | descr | table_rows | +------+---------+-------------------+------------+ | p0 | a,b | 0,10 | 0 | | p1 | a,b | 10,20 | 1 | | p2 | a,b | 10,MAXVALUE | 0 | | p3 | a,b | MAXVALUE,MAXVALUE | 0 | +------+---------+-------------------+------------+ 4 rows in set (0.01 sec) 他的比較原則以下

咱們在看一個例子 mysql> insert into m_num values (10,25); Query OK, 1 row affected (0.01 sec)

mysql> select partition_name part , partition_expression expr, partition_description descr, table_rows from information_schema.partitions where table_schema=schema() and table_name='m_num'; +------+---------+-------------------+------------+ | part | expr | descr | table_rows | +------+---------+-------------------+------------+ | p0 | a,b | 0,10 | 0 | | p1 | a,b | 10,20 | 1 | | p2 | a,b | 10,MAXVALUE | 1 | | p3 | a,b | MAXVALUE,MAXVALUE | 0 | +------+---------+-------------------+------------+ 4 rows in set (0.00 sec) Hash分區

hash分區主要用來分散熱點讀,確保數據在預先知道分區數目,儘量的平均分佈,在數據進行分區的時候,使用一個散列函數,計算數據到那個分區.

hash分區分爲兩類 常規hash和線性hash分區,常規分區是使用模運算計算,而線性hash是一個線性的2的冪運算規則。

咱們使用 partition by hash (expr) partitions num實現

mysql> create table emp_hash( -> id int not null, -> name varchar(20), -> store_id int not null -> ) -> partition by hash (store_id) partitions 4; Query OK, 0 rows affected (0.14 sec) hash分區的數據是按照N=MOD(expr,num)計算的,好比我插入一個store_id=234的數據,那麼他存儲的數據計算在N=MOD(234,4)=2 分區。

mysql> insert into emp_hash values (1,'jiepi',234); Query OK, 1 row affected (0.00 sec)

mysql> explain partitions select * from emp_hash where store_id=234 \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: emp_hash partitions: p2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 2 Extra: Using where 1 row in set (0.00 sec) expr能夠是一個表達式也能夠是一某列的值,當進行插入刪除更新操做的時候,這個表達式都要從新計算一次,因此在表達式比較複雜的時候,仍是很消耗性能的,建議不要使用這種分區方式。

Hash分區在增長分區也是一個比較麻煩的事情,由於要把之前的數據從新計算分配到新的分區的需求,所以咱們還有一種線性Hash分區,分區函數是一個線性的2的冪的運算規則。比常規hash分區多了一個linear.

mysql> create table emp_hash_linear( -> id int not null, -> name varchar(20), -> store_id int not null -> ) -> partition by linear hash (store_id) partitions 4; 他的就算方式以下公式 首先,找到下一個大於等於num的2的冪,這個值爲V,V經過下面公式計算,V=Power(2,Ceiling(Log(2,num)))

其次,設置N=F(column_list)&(V-1),

當N>=num,使用V=Ceiling(V/2),設置N=N&(V-1),N就是分區的位置,不然,上一步計算的N就是分區的位置。

mysql> insert into emp_hash_linear values (1,'jiepi',234); Query OK, 1 row affected (0.01 sec)

mysql> explain partitions select * from emp_hash_linear where store_id=234 \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: emp_hash_linear partitions: p2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 2 Extra: Using where 1 row in set (0.00 sec) Key分區 KEY分區和HASH分區相似,使用hash進行分區,只不過Hash分區支持自定義表達式,而key不支持,使用的是mysql服務器提供的HASH函數,同時hash只支持整數分區,而key分區除了Text和BLOB其餘類型都支持, mysql> create table emp_key( -> id int not null, -> name varchar(20), -> job varchar(20) -> ) -> partition by key (job) partitions 4 -> ; Query OK, 0 rows affected (0.11 sec)

mysql> create table emp_key_primary( -> id int not null, -> name varchar(20), -> job varchar(20), -> primary key (id) -> ) -> partition by key () partitions 4; Query OK, 0 rows affected (0.10 sec)

mysql> create table emp_key_unique( -> id int not null, -> name varchar(20), -> job varchar(20), -> unique key (id) -> ) -> partition by key () partitions 4; Query OK, 0 rows affected (0.11 sec) 須要注意的是,咱們能夠不指定分區間,默認會選取主鍵,其次是惟一鍵做爲分區間,若是沒有主鍵和惟一鍵,就不能不指定分區鍵了。key分區也是使用線性2的冪計算出數據在哪一個分區。當咱們處理大量記錄時,可以有效的分散熱點。 Mysql分區處理NULL值的方式

mysql不由止在分區鍵上使用null,mysql是把null值按照最小值,或者零值進行處理,range分區是按照最小值處理,list分區中,null值必須出如今枚舉中,不然不被接受,Hash和key分區,把null按照零值處理。

分區管理

添加,刪除,從新定義分區處理上,range和list 語法基本一直,咱們來來看一下

range刪除分區

先建立range分區,再插入數據,查看數據在p2,在使用

alter table range_test drop partition p2; mysql> create table range_test( -> id int not null, -> separated date not null default '9999-12-31', -> store_id int not null -> ) -> partition by range(year(separated))( -> partition p0 values less than (1995), -> partition p1 values less than (2000), -> partition p2 values less than (2005), -> partition p3 values less than (2015) -> ); Query OK, 0 rows affected (0.10 sec)

mysql> insert into range_test values (1,'2002-12-01',1); Query OK, 1 row affected (0.00 sec)

mysql> select partition_name part , -> partition_expression expr, -> partition_description descr, -> table_rows from -> information_schema.partitions -> where table_schema=schema() -> and table_name='range_test'; +------+-----------------+-------+------------+ | part | expr | descr | table_rows | +------+-----------------+-------+------------+ | p0 | year(separated) | 1995 | 0 | | p1 | year(separated) | 2000 | 0 | | p2 | year(separated) | 2005 | 1 | | p3 | year(separated) | 2015 | 0 | +------+-----------------+-------+------------+ 4 rows in set (0.00 sec)

mysql> alter table range_test drop partition p2; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> select partition_name part , -> partition_expression expr, -> partition_description descr, -> table_rows from -> information_schema.partitions -> where table_schema=schema() -> and table_name='range_test'; +------+-----------------+-------+------------+ | part | expr | descr | table_rows | +------+-----------------+-------+------------+ | p0 | year(separated) | 1995 | 0 | | p1 | year(separated) | 2000 | 0 | | p3 | year(separated) | 2015 | 0 | +------+-----------------+-------+------------+ 3 rows in set (0.00 sec) 2.range添加分區

注意的是range分區只能在最大端增長分區,不然會報錯 mysql> alter table range_test add partition ( partition p4 values less than (2030)); Query OK, 0 rows affected (0.07 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table range_test\G *************************** 1. row *************************** Table: range_test Create Table: CREATE TABLE range_test ( id int(11) NOT NULL, separated date NOT NULL DEFAULT '9999-12-31', store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (year(separated)) (PARTITION p0 VALUES LESS THAN (1995) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (2000) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (2015) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2030) ENGINE = InnoDB) */ 1 row in set (0.00 sec)

mysql> alter table range_test add partition ( partition p5 values less than (2025)); ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition 3.range從新定義分區

mysql> show create table range_test\G; *************************** 1. row *************************** Table: range_test Create Table: CREATE TABLE range_test ( id int(11) NOT NULL, separated date NOT NULL DEFAULT '9999-12-31', store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (year(separated)) (PARTITION p0 VALUES LESS THAN (1995) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (2000) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (2015) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2030) ENGINE = InnoDB) */ 1 row in set (0.00 sec) ERROR: No query specified

mysql> alter table range_test reorganize partition p3 into( -> partition p2 values less than (2005), -> partition p3 values less than (2015)); Query OK, 0 rows affected (0.14 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table range_test\G *************************** 1. row *************************** Table: range_test Create Table: CREATE TABLE range_test ( id int(11) NOT NULL, separated date NOT NULL DEFAULT '9999-12-31', store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (year(separated)) (PARTITION p0 VALUES LESS THAN (1995) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (2000) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (2005) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (2015) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2030) ENGINE = InnoDB) */ 1 row in set (0.00 sec) 4.list分區從新定義分區

mysql> show create table list_test\G *************************** 1. row *************************** Table: list_test Create Table: CREATE TABLE list_test ( id int(11) NOT NULL, separated date NOT NULL DEFAULT '9999-12-31', store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (store_id) (PARTITION p0 VALUES IN (3,5) ENGINE = InnoDB, PARTITION p1 VALUES IN (1,2) ENGINE = InnoDB, PARTITION p2 VALUES IN (4,7) ENGINE = InnoDB, PARTITION p3 VALUES IN (6) ENGINE = InnoDB) */ 1 row in set (0.00 sec)

mysql> alter table list_test add partition (partition p4 values in (8)); Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table list_test \G *************************** 1. row *************************** Table: list_test Create Table: CREATE TABLE list_test ( id int(11) NOT NULL, separated date NOT NULL DEFAULT '9999-12-31', store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (store_id) (PARTITION p0 VALUES IN (3,5) ENGINE = InnoDB, PARTITION p1 VALUES IN (1,2) ENGINE = InnoDB, PARTITION p2 VALUES IN (4,7) ENGINE = InnoDB, PARTITION p3 VALUES IN (6) ENGINE = InnoDB, PARTITION p4 VALUES IN (8) ENGINE = InnoDB) */ 1 row in set (0.00 sec)

mysql> alter table list_test reorganize partition p2 ,p3,p4 into ( -> partition p2 values in (4), -> partition p3 values in (6), -> partition p4 values in (7,8)); Query OK, 0 rows affected (0.19 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table list_test\G *************************** 1. row *************************** Table: list_test Create Table: CREATE TABLE list_test ( id int(11) NOT NULL, separated date NOT NULL DEFAULT '9999-12-31', store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST (store_id) (PARTITION p0 VALUES IN (3,5) ENGINE = InnoDB, PARTITION p1 VALUES IN (1,2) ENGINE = InnoDB, PARTITION p2 VALUES IN (4) ENGINE = InnoDB, PARTITION p3 VALUES IN (6) ENGINE = InnoDB, PARTITION p4 VALUES IN (7,8) ENGINE = InnoDB) */ 1 row in set (0.01 sec) HASH和KEY分區管理 1.減小Hash分區

mysql> create table hash_test( -> id int not null, -> name varchar(10), -> store_id int not null -> ) -> partition by hash(store_id) partitions 4; Query OK, 0 rows affected (0.09 sec)

mysql> alter table hash_test coalesce partition 2; Query OK, 0 rows affected (0.16 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table hash_test \G *************************** 1. row *************************** Table: hash_test Create Table: CREATE TABLE hash_test ( id int(11) NOT NULL, name varchar(10) DEFAULT NULL, store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH (store_id) PARTITIONS 2 */ 1 row in set (0.00 sec) 2.增長hash分區

mysql> alter table hash_test add partition partitions 8; Query OK, 0 rows affected (0.32 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table hash_test\G *************************** 1. row *************************** Table: hash_test Create Table: CREATE TABLE hash_test ( id int(11) NOT NULL, name varchar(10) DEFAULT NULL, store_id int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY HASH (store_id) PARTITIONS 10 */ 1 row in set (0.00 sec) 注意alter table add partition partitions n 新增hash分區或key分區是在原表上再添加n個分區,不是增長到n個分區。 但願此文對你們有所幫助,也但願你們持續關注轉載。關注公衆號獲取相關資料請回復:typescript,springcloud,springboot,nodejs,nginx,mq,javaweb,java併發實戰,java併發高級進階,實戰java併發,極客時間dubbo,kafka,java面試題,ES,zookeeper,java入門到精通,區塊鏈,java優質視頻,大數據,kotlin,瞬間之美,HTML與CSS,深刻體驗java開發,web開發CSS系列,javaweb開發詳解,springmvc,java併發編程,spring源碼,python,go,redis,docker,即獲取相關資料。

掃碼關注

微信掃一掃 關注該公衆號

相關文章
相關標籤/搜索