Mysql数据按天分区,定期删除,及分区索引

通过SQL直接增删分区

 

分区的原因:

   1、可以把一些归类的数据放在一个分区中,可以减少服务器检查数据的数量加快查询。

   2、方便维护,通过删除分区来删除老的数据。

   3、分区数据可以被分布到不同的物理位置,可以做分布式有效利用多个硬盘驱动器。

 

MySQL可以建立四种分区类型的分区:

    1、RANGE 分区:基于属于一个给定连续区间的列值,把多行分配给分区。

    2、LIST 分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。  www.jb51.net 

    3、HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。

    4、KEY 分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL 服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

一般用得多的是range分区和list分区。

 

需求:

  1.报表(消耗日志)需要按天分区

  2.只保留一个月数据

  3.这里是新建空表,创建分区,然后导入数据,再每天新增,删除分区

      4.如需在原表上新建分区,并每天新增删除分区的,请移步:https://www.cnblogs.com/garfieldcgf/p/10143367.html

 

方案: 1

  1.创建一个空表,并创建30天分区

      2.通过定时任务,每天删除分区,新建分区,保持分区总量不变即可

      3.导入数据或定时生成数据即可

 

注意:

  1.分区索引问题,全局索引未必生效,需Explain看一下

      2.新建分区索引,不会

      3.强制使用唯一索引,直接爆炸,原800万左右的数据,explain后rows 大于1.4个亿

      4.分区字段必须包含在主键中

      5.注意使用drop、truncate等操作分区后,据说全局索引会失效,就是我们建表的索引,需要我们手动

 

这里以range分区为例,如下:

 

1、新建表

CREATE TABLE `ug_stats_material_daily` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `dt` bigint(20) NOT NULL COMMENT '日期,如20200512',
`hr` int(10) NOT NULL COMMENT '小时,0-23', `cdt`
bigint(20) NOT NULL DEFAULT '0' COMMENT '素材创建日期', `mid` int(10) NOT NULL COMMENT '媒体id 1-广点通 2-头条 3-快手 ', `pid` bigint(20) NOT NULL DEFAULT '0' COMMENT '项目ID', `account_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '账户ID', `ctype` int(10) NOT NULL DEFAULT '0' COMMENT '创意类型,0:未知,1图片,2视频,3文案', `material_dna` varchar(255) NOT NULL DEFAULT '', `material_dna_id` bigint(20) NOT NULL, `material_id` int(11) NOT NULL DEFAULT '0', `imp` int(2) unsigned NOT NULL DEFAULT '0' COMMENT '素材曝光', `mimp` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '素材曝光,仅快手', `clk` bigint(20) unsigned NOT NULL DEFAULT '0', `landing_clk` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '行为点击', `act` bigint(20) unsigned NOT NULL DEFAULT '0', `waken` bigint(20) unsigned NOT NULL DEFAULT '0', `reg` bigint(20) unsigned NOT NULL DEFAULT '0', `active` int(11) DEFAULT NULL COMMENT '次留', `pay` bigint(20) unsigned NOT NULL DEFAULT '0', `price` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '渠道消耗,单位分', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`,`dt`), UNIQUE KEY `dt_mid_ctype_pid_accountid_mdnaid` (`dt`,`mid`, `ctype`,`pid`, `account_id`,`material_dna_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 /*!50100 PARTITION BY RANGE (dt) ( PARTITION p_20220601 VALUES LESS THAN (20220602) ENGINE = InnoDB, PARTITION p_20220602 VALUES LESS THAN (20220603) ENGINE = InnoDB, PARTITION p_20220603 VALUES LESS THAN (20220604) ENGINE = InnoDB, PARTITION p_20220604 VALUES LESS THAN (20220605) ENGINE = InnoDB, PARTITION p_20220605 VALUES LESS THAN (20220606) ENGINE = InnoDB, PARTITION p_20220606 VALUES LESS THAN (20220607) ENGINE = InnoDB) */;
库名:km
表名:ug_stats_material_daily

 

2、查看分区

select partition_name part, partition_expression expr, partition_description descr, table_rows from  INFORMATION_SCHEMA.partitions  where TABLE_SCHEMA="km" AND TABLE_NAME="ug_stats_material_daily";

 

3、手动添加分区

ALTER TABLE km.ug_stats_material_daily ADD PARTITION (PARTITION 'p_20220607' VALUES LESS THAN (20220608));

 

4、删除分区数据(分区仍在,但会释放内存,与delete有区别)

 alter table 上述表名 truncate partition p_20220601;  

 

5、直接删除分区及数据

ALTER TABLE 表名 DROP PARTITION p_20220601;

 

6、分区的合并

下面的SQL,将p201001 - p201009 合并为3个分区p2010Q1 - p2010Q3

ALTER TABLE 表名 REORGANIZE PARTITION p201001,p201002,p201003,p201004,p201005,p201006,p201007,p201008,p201009 INTO

(

PARTITION p2010Q1 VALUES LESS THAN (201004),  

PARTITION p2010Q2 VALUES LESS THAN (201007),

PARTITION p2010Q3 VALUES LESS THAN (201010)

);

 

7、分区的拆分

下面的SQL,将p2010Q1 分区,拆分为s2009 与s2010 两个分区

ALTER TABLE sale_data REORGANIZE PARTITION p2010Q1 INTO (
 PARTITION s2009 VALUES LESS THAN (201001),
 PARTITION s2010 VALUES LESS THAN (201004)
);

 

分区索引的局限:
1,所有分区都要使用同样的引擎。
2,分区表的每一个唯一索引必须包含由分区函数引用的列。
3,mysql能避免查询所有的分区,但仍然锁定了所有分区。
4,分区函数能使用的函数和表达式有限,
5,分区不支持外键。 
6,不能使用LOAD INDEX INTO CACHE
7,分区并不能总是改善性能,要进行性能评测。
例如可以使用expalin partitions 来查看查询语句是否使用分区过滤了数据:

mysql> explain partitions select * from fenqubiao where day<'2011-09-12';
+----+-------------+-----------+---------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table     | partitions    | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-----------+---------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | fenqubiao | p_2010,p_2011 | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+-----------+---------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

 

 

 

解存储过程创建分区(建议略过)

以下为手动建立分区的存储过程demo,用于了解存储过程

-- SELECT DATE_FORMAT(DATE_SUB(curdate(),INTERVAL + 14 DAY),"p_%Y%m%d");
-- SELECT DATE_FORMAT(DATE_SUB(curdate(),INTERVAL + 12 DAY),"%Y%m%d");

-- 有一张空白表,也可以是有数据的  
DELIMITER $$
USE `mydatebase`$$
DROP PROCEDURE IF EXISTS `create_partition_today`$$
CREATE PROCEDURE `create_partition_today`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
  BEGIN
    DECLARE DAYS_ENDTIME INT;
    DECLARE PARTITIONNAME VARCHAR(16);
    SET PARTITIONNAME = DATE_FORMAT(DATE_SUB(curdate(),INTERVAL +13 DAY),"p_%Y%m%d");
    SET DAYS_ENDTIME = DATE_FORMAT(DATE_SUB(curdate(),INTERVAL +12 DAY),"%Y%m%d");
    SET @SQL = CONCAT('ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
                        ' PARTITION BY RANGE (dt)
    (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', DAYS_ENDTIME, '))');
    PREPARE STMT FROM @SQL;
    EXECUTE STMT;
    DEALLOCATE PREPARE STMT;
  END$$
DELIMITER ;


CALL create_partition_today('mydatebase', 'test_ug_stats_material_hourly'); -- 分区后还需处理历史数据,由于是空表,所以未处理,如有需要,参看上文:方法一

ALTER TABLE test_ug_stats_material_hourly ADD PARTITION (PARTITION p_20211115 VALUES LESS THAN (20211116));
ALTER TABLE test_ug_stats_material_hourly DROP PARTITION p_20211101;

SELECT table_name, partition_name, table_rows FROM information_schema.partitions WHERE table_name='test_ug_stats_material_hourly';

 

分区索引:

对索引进行分区有两种方法:
1) 随表对索引完成相应的分区:这也称为局部分区索引(locally partitioned index)。
每个表分区都有一个索引分区,而且只索引该表分区。一个给定索引分区中的所有条目都指向一个表分区,表分区中的所有行都表示在一个索引分区中。

2)按区间对索引分区:这也称为全局分区索引(globally partitioned index)。
索引按区间分区或者按散列(10g之后)分区,一个索引分区可能指向任何(和所有)表分区。
由于全局索引只按区间或散列分区,如果希望有一个列表或组合分区索引,就必须使用局部索引。而局部索引会使用底层表相同的机制分区。

使用LOCAL关键字创建局部分区索引。
局部分区索引使用和基表相同的分区来保存索引。
如果使用一个局部索引来保证惟一性约束(PRIMARY KEY或者UNIQUE),那么分区键必须包括在约束本身中。

--创建分区表和分区索引
创建表:
create table test(
c1 int,
c2 varchar2(16),
c3 varchar2(64),
c4 int
constraint pk_ta_c1 primary key(c1)
)partition by range(c1)(
partition p1 values less than(10000000),
partition p2 values less than(20000000),
partition p3 values less than(30000000),
partition p4 values less than(maxvalue)
);
建立分区索引:
create index idx_test_c2 on test(c2) local (partition p1,partition p2,partition p3,parition p4);
或者create index idx_test_c2 on test(c2) local;

删除分区索引:https://blog.csdn.net/kaertiger/article/details/6927657

 

 

posted @ 2021-11-10 11:36  _Eternity味道  Views(2673)  Comments(0Edit  收藏  举报