按月份分區(qū),這樣再使用分區(qū)字段時(shí)間來查詢數(shù)據(jù)將會(huì)很快,因?yàn)檫@樣只需要掃描指定的分區(qū)。
1、創(chuàng)建表,并使用RANGE COLUMNS分區(qū)。按創(chuàng)建時(shí)間create_time字段分區(qū);分區(qū)名使用p0、p1、p2、p3 .. 的形式;create_time字段小于2019-01-01的數(shù)據(jù)將進(jìn)入p0 分區(qū),依次類推。。
CREATE TABLE "box_fenqu" (
"id" bigint(36) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
"create_by" varchar(50) DEFAULT NULL COMMENT '創(chuàng)建人',
"create_time" datetime NOT NULL COMMENT '創(chuàng)建日期',
"update_by" varchar(50) DEFAULT NULL COMMENT '更新人',
"update_time" datetime DEFAULT NULL COMMENT '更新日期',
"sys_org_code" varchar(64) DEFAULT NULL COMMENT '所屬部門',
"status" int(10) DEFAULT '0' COMMENT '狀態(tài)',
"number" varchar(32) DEFAULT NULL COMMENT '編號(hào)',
"zi_number" varchar(32) DEFAULT NULL COMMENT '自編號(hào)',
"house_address" varchar(32) DEFAULT NULL COMMENT '倉(cāng)庫地址',
"sb_number" varchar(32) DEFAULT NULL COMMENT '設(shè)備id',
"point_id" varchar(32) DEFAULT NULL COMMENT '投放點(diǎn)id',
"point" varchar(32) DEFAULT NULL COMMENT '投放點(diǎn)',
"confirm" int(32) DEFAULT '0' COMMENT '商戶/企業(yè)用戶確認(rèn)入庫,默認(rèn)為0(未確認(rèn))1是已確認(rèn)',
"last_point" varchar(32) DEFAULT NULL COMMENT '最近一次投放點(diǎn)名',
PRIMARY KEY ("id","create_time") USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2120001 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC
PARTITION BY RANGE COLUMNS(create_time)
(PARTITION p0 VALUES LESS THAN ('2019-01-01') ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN ('2019-02-01') ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN ('2019-03-01') ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN ('2019-04-01') ENGINE = InnoDB,
PARTITION p4 VALUES LESS THAN ('2019-05-01') ENGINE = InnoDB,
PARTITION p5 VALUES LESS THAN ('2019-06-01') ENGINE = InnoDB,
PARTITION p6 VALUES LESS THAN ('2019-07-01') ENGINE = InnoDB,
PARTITION p7 VALUES LESS THAN ('2019-08-01') ENGINE = InnoDB,
PARTITION p8 VALUES LESS THAN ('2019-09-01') ENGINE = InnoDB,
PARTITION p9 VALUES LESS THAN ('2019-10-01') ENGINE = InnoDB,
PARTITION p10 VALUES LESS THAN ('2019-11-01') ENGINE = InnoDB,
PARTITION p11 VALUES LESS THAN ('2019-12-01') ENGINE = InnoDB,
PARTITION p12 VALUES LESS THAN ('2020-01-01') ENGINE = InnoDB,
PARTITION p13 VALUES LESS THAN ('2020-02-01') ENGINE = InnoDB,
PARTITION p14 VALUES LESS THAN ('2020-03-01') ENGINE = InnoDB,
PARTITION p15 VALUES LESS THAN ('2020-04-01') ENGINE = InnoDB,
PARTITION p16 VALUES LESS THAN ('2020-05-01') ENGINE = InnoDB,
PARTITION p17 VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB)
2、創(chuàng)建存儲(chǔ)過程proc_create_partition,用它來直接對(duì)box_fenqu表進(jìn)行分區(qū)。其實(shí)就是將分區(qū)名加1,如p2加1就是p3;指定的日期范圍就是往后面進(jìn)一個(gè)月,保證最新的分區(qū)總是MAXVALUES的 ,如20200401就變成20200401和20200501,其中20200401指定范圍,20200501為MAXVALUES
CREATE DEFINER="root"@"%" PROCEDURE "proc_create_partition"(in_tbname VARCHAR(64))
BEGIN
SELECT DATABASE() INTO @dbname;
SET @tbname = in_tbname;
#查詢表的最近一次分區(qū)的名字,這里按自然數(shù)遞增的。比如0,1,2,4。去掉 p
SELECT
REPLACE (partition_name, 'p', '') INTO @PMAX
FROM
INFORMATION_SCHEMA.PARTITIONS
WHERE
TABLE_SCHEMA = @dbname
AND table_name = @tbname
ORDER BY
partition_ordinal_position DESC
LIMIT 1;
#查詢表的最近一次分區(qū)的指定時(shí)間,比如最近時(shí)間的分區(qū)時(shí) 2020.04.01
SELECT
REPLACE(partition_description, '\'', '') INTO @DNAME
FROM
INFORMATION_SCHEMA.PARTITIONS
WHERE
TABLE_SCHEMA = @dbname
AND table_name = @tbname
ORDER BY
partition_ordinal_position DESC
LIMIT 1, 1;
SET @t=CONCAT('alter table `',@dbname,'`.',@tbname,' reorganize partition p',@PMAX,
' into(partition p',@PMAX,' values less than (''',date(DATE_ADD(@DNAME,INTERVAL 1 MONTH)),'''),',
'partition p',@PMAX+1,' values less than MAXVALUE)');
SELECT @t;
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
COMMIT;
END
這樣傳入box_fenqu表名即可進(jìn)行增加分區(qū)了: CALL proc_create_partition('box_fenqu');
3、創(chuàng)建mysql事件,定時(shí)調(diào)度分區(qū);下面的事件到的意思就是從2020-05-03 00:00:00開始,每過一個(gè)月就執(zhí)行下CALL proc_create_partition('box_fenqu')
CREATE DEFINER=`root`@`%` EVENT `e_create_partition`
ON SCHEDULE EVERY 1 MONTH STARTS '2020-05-03 00:00:00'
ON COMPLETION PRESERVE DISABLE
DO CALL proc_create_partition('box_fenqu')
4、如果有多個(gè)表需要都需要定時(shí)的動(dòng)態(tài)增加分區(qū)的話,就可以再寫個(gè)存儲(chǔ)如下,這個(gè)存儲(chǔ)過程將對(duì)當(dāng)前庫下所有分區(qū)表都進(jìn)行遍歷,然后增加分區(qū)
CREATE DEFINER="root"@"%" PROCEDURE "proc_create_partition_all"()
BEGIN
DECLARE tbname varchar(32);
DECLARE tmpSql varchar(256);
DECLARE done INT DEFAULT FALSE ;
#查詢已手動(dòng)分區(qū)的表
DECLARE part_cursor CURSOR FOR (SELECT DISTINCT table_name FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA = DATABASE() AND partition_expression IS NOT NULL AND table_name NOT LIKE '%bak');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
#循環(huán)對(duì)表添加分區(qū)
OPEN part_cursor;
myLoop: LOOP
FETCH part_cursor INTO tbname;
IF done THEN
LEAVE myLoop;
END IF;
#調(diào)用分區(qū)存儲(chǔ)過程
CALL proc_create_partition(tbname);
COMMIT;
END LOOP myLoop;
CLOSE part_cursor;
END
5、mysql允許創(chuàng)建的分區(qū)數(shù)量有限,因此我們可以根據(jù)業(yè)務(wù)的情況。定期刪除已經(jīng)不需要的分區(qū)
6、查詢有數(shù)據(jù)的最新日期/月份
select REPLACE(partition_description, '\'', '') date from INFORMATION_SCHEMA.PARTITIONS where TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='box_fenqu' AND table_rows != 0
ORDER BY REPLACE(partition_description, '\'', '') desc limit 1
查詢有數(shù)據(jù)的數(shù)據(jù)條數(shù)
select table_rows from INFORMATION_SCHEMA.PARTITIONS where TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='box_fenqu' AND table_rows != 0
ORDER BY REPLACE(partition_description, '\'', '') desc limit 1
7、插入數(shù)據(jù)測(cè)試,編寫存儲(chǔ)過程如下
CREATE DEFINER="root"@"localhost" PROCEDURE "insert_box_fq"(in max_num int(10),in sDate datetime,in eDate datetime)
begin
declare i int default 0;
/*把a(bǔ)utocommit設(shè)置成0*/
set autocommit= 0;
repeat
set i=i+1;
INSERT INTO `test`.`box_fenqu`(`create_by`, `create_time`, `update_by`, `update_time`, `sys_org_code`, `status`, `number`, `zi_number`, `house_address`, `sb_number`, `point_id`, `point`, `confirm`, `last_point`) VALUES (rand_string(3), getDateTime(sDate,eDate), rand_string(3), now(), 'A03', 0, rand_string(3), 'A001', '倉(cāng)庫1', rand_string(3), rand_string(3), NULL, 1, rand_string(3));
until i=max_num end repeat;
commit;
end
插入10萬條 call insert_box_fq(100000,'2019-01-01 00:00:00',now())
8、查詢各個(gè)分區(qū)數(shù)據(jù)情況
SELECT
PARTITION_NAME AS '分區(qū)名',
TABLE_ROWS AS '記錄數(shù)' ,
PARTITION_DESCRIPTION '范圍'
FROM
information_schema.PARTITIONS
WHERE
table_schema = 'test'
AND table_name = 'box_fenqu';
思考分區(qū)結(jié)合分頁
既然是按日期分區(qū),那么我們?cè)诜猪摬樵儠r(shí)就可以使用日期。如下我查詢最新的10條數(shù)據(jù)。效率非常低,因?yàn)樾枰獟呙杷械姆謪^(qū)。但是事實(shí)上我們只需要10條而已,只需要在最新的分區(qū)中查找。若最新的分區(qū)記錄數(shù)大于等于10那么就需要前移動(dòng)一個(gè)月份,另外掃描一個(gè)分區(qū)。依次類推。我想這樣應(yīng)該查詢效率很快了吧
SELECT * FROM box_fenqu ORDER BY create_time DESC LIMIT 10
這樣需要寫一個(gè)存儲(chǔ)過程來查詢,將limit 掃描的分區(qū)只鎖定在需要的分區(qū)里