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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM