通過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