Mysql按天自動表分區教程
前言
在使用mysql時,往往用一張表來存放數據,不同的業務可能產生的數據量也不同,有的業務可能一天需要插入幾萬條數據,也有的則更多,即使量很小日積月累數據庫表的數據堆積也會越來越多,需要人工去刪除數據,當數據達到百萬或千萬級別時,mysql查詢速度明顯下降,性能也隨之下降,解決該問題的辦法有很多,比如添加索引、優化SQL,但這都只是治標不治本的做法,無法從根本上提高Mysql的性能和查詢速度。
什么是表分區?
mysql數據庫中的數據是以文件的形勢存在磁盤上的,默認放在/mysql/data下面(可以通過my.cnf中的datadir來查看),一張表主要對應着三個文件,一個是frm存放表結構的,一個是myd存放表數據的,一個是myi存表索引的。如果一張表的數據量太大的話,那么myd,myi就會變的很大,查找數據就會變的很慢,這個時候我們可以利用mysql的分區功能,在物理上將這一張表對應的三個文件,分割成許多個小塊,這樣呢,我們查找一條數據時,就不用全部查找了,只要知道這條數據在哪一塊,然后在那一塊找就行了。如果表的數據太大,可能一個磁盤放不下,這個時候,我們可以把數據分配到不同的磁盤里面去。
表分區,是指根據一定規則,將數據庫中的一張表分解成多個更小的,容易管理的部分。從邏輯上看,只有一張表,但是底層卻是由多個物理分區組成。
創建測試數據庫
create database test charset=utf8;
- 1
創建測試表
use test; // 先切換到test數據庫
create table test_log
(
time datetime,
msg varchar(2000)
)
- 1
- 2
- 3
- 4
- 5
- 6
手動進行分區
對自動分區的表必須是在該表有手動分區的前提之下才能進行;對以下代碼稍做解釋,less than 的意思是小於的意思,所以p20191001這個分區里面存放的數據都是比2019年10月1日之前的數據,以此類推,p20191002存放的是10月1日的數據,p20191003存放的是10月2日的數據。
批量進行分區
alter table test_log partition by range columns(time)(
partition p20191001 values less than('2019-10-01'),
partition p20191002 values less than('2019-10-02'),
partition p20191003 values less than('2019-10-03'),
partition p20191003 values less than('2019-10-04')
);
- 1
- 2
- 3
- 4
- 5
- 6
單條增加分區
alter table test_log add partition (partition p20191003 values less than('2019-10-03'));
- 1
刪除分區命令
因為數據都是存放在一個一個的分區當中,所以當分區刪除的時間,對應的數據也會刪除,例如以下命令會把10月3日的數據刪除,可自行驗證!
alter table test_log drop partition p20191004;
- 1
插入數據
insert into test_log values('2019-10-01 10:11:13', 'hi');
insert into test_log values('2019-10-02 10:12:10', 'ni');
insert into test_log values('2019-10-03 10:12:10', 'hao');
- 1
- 2
- 3
查看表分區
select partition_name, partition_description as val from information_schema.partitions
where table_name='test_log' and table_schema='test';
- 1
- 2
創建增加分區和刪除分區代碼
注意:
1.以下代碼可以手動mysql -u root -p登錄到mysql執行
2.以下代碼有table_name和table_schema是表和數據庫名,一共6處,另外每次新增幾個分區,刪除幾個舊分區,找到相應位置,根據需要自行修改,程序員多多少少大致能看懂的。
3.執行到delimiter ;繼續按回車執行完畢,否則會出現無法執行命令的情況。
delimiter $$
DROP PROCEDURE IF EXISTS pro_test_log
$$
CREATE PROCEDURE pro_test_log()
BEGIN
DECLARE v_sysdate date;
DECLARE v_mindate date;
DECLARE v_maxdate date;
DECLARE v_pt varchar(20);
DECLARE v_maxval varchar(20);
DECLARE i int;
/*增加新分區代碼,執行時,不要復制此行*/
SELECT max(cast(replace(partition_description, '''', '') AS date)) AS val
INTO v_maxdate
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'test_log' AND TABLE_SCHEMA = 'test';
set v_sysdate = sysdate();
WHILE v_maxdate <= (v_sysdate + INTERVAL 3 DAY) DO
SET v_pt = date_format(v_maxdate+ INTERVAL 1 DAY ,'%Y%m%d');
SET v_maxval = date_format(v_maxdate + INTERVAL 1 DAY, '%Y-%m-%d');
SET @sql = concat('alter table test_log add partition (partition p', v_pt, ' values less than(''', v_maxval, '''))');
-- SELECT @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET v_maxdate = v_maxdate + INTERVAL 1 DAY;
END WHILE;
/*刪除舊分區,執行時,不要復制此行*/
SELECT min(cast(replace(partition_description, '''', '') AS date)) AS val
INTO v_mindate
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'test_log ' AND TABLE_SCHEMA = 'test';
WHILE v_mindate <= (v_sysdate - INTERVAL 6 DAY) DO
SET v_pt = date_format(v_mindate - INTERVAL 1 DAY,'%Y%m%d');
SET @sql = concat('alter table test_log drop partition p', v_pt);
-- SELECT @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET v_mindate = v_mindate + INTERVAL 1 DAY;
END WHILE;
END$$
delimiter ;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
手動調用存儲程序命令
每次新增分區和刪除舊分區需要手動執行以下命令執行,一般一天執行一次,或都一小時都可以,但是我們人不能每天上班都去執行一次,接下來我們會使用事件,讓mysql自動每天執行。
call proc_test_log;
- 1
開啟事件
使用mysql的事件實現定時分區,mysql默認是不會開啟事件例程的,需要手動打開,查看是否打開。
新建event事件
為了測試方便,間隔設置為分鍾, 也可設置成小時 24 hour
DELIMITER $$
drop event if exists auto_pt $$
create event auto_pt
on schedule
every 1 minute
starts '2019-10-01 13:19:02'
do
BEGIN
call proc_test_log();
END$$
delimiter ;