搞懂MySQL分區

一.InnoDB邏輯存儲結構

  首先要先介紹一下InnoDB邏輯存儲結構和區的概念,它的全部數據都被邏輯地存放在表空間,表空間又由段,區,頁組成。mysql

  段就是上圖的segment區域,常見的段有數據段、索引段、回滾段等,在InnoDB存儲引擎中,對段的管理都是由引擎自身所完成的。sql

  區就是上圖的extent區域,區是由連續的頁組成的空間,不管頁的大小怎麼變,區的大小默認老是爲1MB。爲了保證區中的頁的連續性,InnoDB存儲引擎一次從磁盤申請4-5個區,InnoDB頁的大小默認爲16kb,即一個區一共有64(1MB/16kb=16)個連續的頁。每一個段開始,先用32頁(page)大小的碎片頁來存放數據,在使用完這些頁以後纔是64個連續頁的申請。這樣作的目的是,對於一些小表或者是undo類的段,能夠開始申請較小的空間,節約磁盤開銷。數據庫

  頁就是上圖的page區域,也能夠叫塊。頁是InnoDB磁盤管理的最小單位。默認大小爲16KB,能夠經過參數innodb_page_size來設置。常見的頁類型有:數據頁,undo頁,系統頁,事務數據頁,插入緩衝位圖頁,插入緩衝空閒列表頁,未壓縮的二進制大對象頁,壓縮的二進制大對象頁等。  函數

 

二.分區概述

分區

  這裏講的分區,此「區」非彼「區」,這裏講的分區的意思是指將同一表中不一樣行的記錄分配到不一樣的物理文件中,幾個分區就有幾個.idb文件,不是咱們剛剛說的區。MySQL在5.1時添加了對水平分區的支持。分區是將一個表或索引分解成多個更小,更可管理的部分。每一個區都是獨立的,能夠獨立處理,也能夠做爲一個更大對象的一部分進行處理。這個是MySQL支持的功能,業務代碼無需改動。要知道MySQL是面向OLTP的數據,它不像TIDB等其餘DB。那麼對於分區的使用應該很是當心,若是不清楚如何使用分區可能會對性能產生負面的影響。性能

  MySQL數據庫的分區是局部分區索引,一個分區中既存了數據,又放了索引。也就是說,每一個區的彙集索引和非彙集索引都放在各自區的(不一樣的物理文件)。目前MySQL數據庫還不支持全局分區。
優化

  不管哪一種類型的分區,若是表中存在主鍵或惟一索引時,分區列必須是惟一索引的一個組成部分。spa

   

三.分區類型

   目前MySQL支持一下幾種類型的分區,RANGE分區,LIST分區,HASH分區,KEY分區。若是表存在主鍵或者惟一索引時,分區列必須是惟一索引的一個組成部分。實戰十有八九都是用RANGE分區。code

RANGE分區

  RANGE分區是實戰最經常使用的一種分區類型,行數據基於屬於一個給定的連續區間的列值被放入分區。可是記住,當插入的數據不在一個分區中定義的值的時候,會拋異常。RANGE分區主要用於日期列的分區,好比交易表啊,銷售表啊等。能夠根據年月來存放數據。若是你分區走的惟一索引中date類型的數據,那麼注意了,優化器只能對YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()這類函數進行優化選擇。實戰中能夠用int類型,那麼只用存yyyyMM就行了。也不用關心函數了。對象

CREATE TABLE `m_test_db`.`Order` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `partition_key` INT NOT NULL,
  `amt` DECIMAL(5) NULL,
  PRIMARY KEY (`id`, `partition_key`)) PARTITION BY RANGE(partition_key) PARTITIONS 5( PARTITION part0 VALUES LESS THAN (201901),  PARTITION part1 VALUES LESS THAN (201902),  PARTITION part2 VALUES LESS THAN (201903),  PARTITION part3 VALUES LESS THAN (201904),  PARTITION part4 VALUES LESS THAN (201905)) ;

  這時候咱們先插入一些數據blog

INSERT INTO `m_test_db`.`Order` (`id`, `partition_key`, `amt`) VALUES ('1', '201901', '1000');
INSERT INTO `m_test_db`.`Order` (`id`, `partition_key`, `amt`) VALUES ('2', '201902', '800');
INSERT INTO `m_test_db`.`Order` (`id`, `partition_key`, `amt`) VALUES ('3', '201903', '1200');

  如今咱們查詢一下,經過EXPLAIN PARTITION命令發現SQL優化器只需搜對應的區,不會搜索全部分區

  若是sql語句有問題,那麼會走全部區。會很危險。因此分區表後,select語句必須走分區鍵。

 

如下3種不是太經常使用,就一筆帶過了。

LIST分區

  LIST分區和RANGE分區很類似,只是分區列的值是離散的,不是連續的。LIST分區使用VALUES IN,由於每一個分區的值是離散的,所以只能定義值。

HASH分區

  說到哈希,那麼目的很明顯了,將數據均勻的分佈到預先定義的各個分區中,保證每一個分區的數量大體相同。

KEY分區

  KEY分區和HASH分區類似,不一樣之處在於HASH分區使用用戶定義的函數進行分區,KEY分區使用數據庫提供的函數進行分區。

 

四.分區和性能

  一項技術,不是用了就必定帶來益處。好比顯式鎖功能比內置鎖強大,你沒玩好可能致使很很差的狀況。分區也是同樣,不是啓動了分區數據庫就會運行的更快,分區可能會給某些sql語句性能提升,可是分區主要用於數據庫高可用性的管理。數據庫應用分爲2類,一類是OLTP(在線事務處理),一類是OLAP(在線分析處理)。對於OLAP應用分區的確能夠很好的提升查詢性能,由於通常分析都須要返回大量的數據,若是按時間分區,好比一個月用戶行爲等數據,則只需掃描響應的分區便可。在OLTP應用中,分區更加要當心,一般不會獲取一張大表的10%的數據,大部分是經過索引返回幾條數據便可。

  好比一張表1000w數據量,若是一句select語句走輔助索引,可是沒有走分區鍵。那麼結果會很尷尬。若是1000w的B+樹的高度是3,如今有10個分區。那麼不是要(3+3)*10次的邏輯IO?(3次彙集索引,3次輔助索引,10個分區)。因此在OLTP應用中請當心使用分區表。

  在平常開發中,若是想查看sql語句的分區查詢結果可使用explain partitions + select sql來獲取,partitions標識走了哪幾個分區。

mysql> explain partitions select * from TxnList where startTime>'2016-08-25 00:00:00' and startTime<'2016-08-25 23:59:00';  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
| id | select_type | table             | partitions | type | possible_keys | key  | key_len | ref  | rows  | Extra       |  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
|  1 | SIMPLE      | ClientActionTrack | p20160825  | ALL  | NULL          | NULL | NULL    | NULL | 33868 | Using where |  
+----+-------------+-------------------+------------+------+---------------+------+---------+------+-------+-------------+  
1 row in set (0.00 sec)  

 

 

 

參考:

《MySQL技術內幕》

第一張圖是從哪裏偷來的忘記了- -!

相關文章
相關標籤/搜索