使用存储过程和事件调度程序在 mysql 中创建动态分区

Dynamic Partition Creation in mysql using stored procedure and event scheduler

我有一个 table,我想通过首先按月对 table 进行分区然后按 ID 进行子分区来创建自动分区方案。

我最近了解到 mysql 不支持自动分区,创建动态分区的唯一方法是通过存储过程和事件调度程序。

我的要求是新条目自动创建到新分区,一年后旧记录自动删除。

我该怎么做?

请给我一些关于如何实现存储过程和事件调度程序以支持动态分区并自动删除旧记录的方法。

这是架构:

CREATE TABLE `ORDER_HISTORY` (
  `Id` bigint(20) NOT NULL,
  `Invoice_Number` varchar(16) NOT NULL,
  `User_Id` int(10) NOT NULL,
  `Store_ID` mediumint(6) NOT NULL,
  `Store_Entity_Id` mediumint(8) NOT NULL,
  `Item_List` blob NOT NULL,
  `Order_Time` datetime NOT NULL,
  `Payment_Time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `Payment_Type` tinyint(2) NOT NULL,
  `Payment_Retry_Attempts` tinyint(1) NOT NULL,
  `Payment_TransactionID` varchar(32) NOT NULL,
  `Sub_Total_Amount` decimal(10,2) NOT NULL DEFAULT '0.00',
  `CGST_Tax_Amount` decimal(6,2) NOT NULL DEFAULT '0.00',
  `SGST_Tax_Amount` decimal(6,2) NOT NULL DEFAULT '0.00',
  `Other_Tax_Amount` decimal(6,2) NOT NULL DEFAULT '0.00',
  `Service_Fee` decimal(6,2) NOT NULL DEFAULT '0.00',
  `Earned_Cashback_Amount` decimal(4,2) NOT NULL DEFAULT '0.00',
  `Used_Cashback_Amount` decimal(4,2) NOT NULL DEFAULT '0.00',
  `Used_Coupon` mediumint(8) DEFAULT NULL,
  `Used_Coupon_Discount` decimal(4,2) NOT NULL DEFAULT '0.00',
  `Grand_Total_Amount` decimal(10,2) NOT NULL DEFAULT '0.00',
  `Status` tinyint(3) NOT NULL,
  `Manager_Id` smallint(5) DEFAULT NULL,
  `Store_Name` varchar(32) DEFAULT NULL,
  `User_Name` varchar(32) DEFAULT NULL,
  `User_Phone_Number` varchar(10) DEFAULT NULL,
  `Manager_Phone_Number` varchar(10) NOT NULL,
  `Manager_Name` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`Id`),
  UNIQUE KEY `Id_UNIQUE` (`Id`),
  KEY `Store_ID_idx` (`Store_ID`),
  KEY `Table_ID_idx` (`Store_Entity_Id`),
  KEY `Phone_Number_idx` (`User_Id`),
  KEY `oh_payment_type_id_fk_idx` (`Payment_Type`),
  KEY `oh_coupon_id_fk_idx` (`Used_Coupon`),
  KEY `oh_status_id_fk_idx` (`Status`),
  KEY `oh_manager_id_fk` (`Manager_Id`),
  CONSTRAINT `oh_coupon_id_fk` FOREIGN KEY (`Used_Coupon`) REFERENCES `COUPONS` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `oh_manager_id_fk` FOREIGN KEY (`Manager_Id`) REFERENCES `MANAGER` (`Id`),
  CONSTRAINT `oh_payment_type_id_fk` FOREIGN KEY (`Payment_Type`) REFERENCES `PAYMENT_TYPES` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `oh_status_id_fk` FOREIGN KEY (`Status`) REFERENCES `STATUS` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `oh_store_entity_id_fk` FOREIGN KEY (`Store_Entity_Id`) REFERENCES `STORE_ENTITY` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `oh_store_id_fk` FOREIGN KEY (`Store_ID`) REFERENCES `STORE` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `oh_user_id_fk` FOREIGN KEY (`User_Id`) REFERENCES `USERS` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

提前致谢!

首先,分区是解决您遇到的问题的最佳用例。原因是您使用的存储引擎 innodb 是基于事务的引擎。因此,它会记录在日志中完成的所有操作,从而获得更高的 I/O 资源。而对于删除甚至它需要更多的资源。但是带有子分区的分区是多余的,因为你需要每年清理一次 table 数据,这样你就可以将 RANGE COLUMN 子句与 cron 作业一起使用,每年 运行 一次。

您可以通过执行以下命令检查您的 MySQL 是否支持 partition

SHOW PLUGINS;

这将显示表格数据,请检查您在 name 列中有 partition,在 Status 列中有 ACTIVE

分区类型:

有两种类型的分区。它们是MySQL不支持的垂直分区(按列分区),第二个是水平分区(按行分区)。

分区定义:

        PARTITION partition_name
        [VALUES
            {LESS THAN {(expr | value_list) | MAXVALUE}
            |
            IN (value_list)}]
        [[STORAGE] ENGINE [=] engine_name]
        [COMMENT [=] 'string' ]
        [DATA DIRECTORY [=] 'data_dir']
        [INDEX DIRECTORY [=] 'index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] tablespace_name]
        [(subpartition_definition [, subpartition_definition] ...)]

解决方案:

第 1 步: 用这样的分区改变 table 模式(参考 link 3)

CREATE TABLE members (
    firstname VARCHAR(25) NOT NULL,
    lastname VARCHAR(25) NOT NULL,
    username VARCHAR(16) NOT NULL,
    email VARCHAR(35),
    joined DATE NOT NULL
)
PARTITION BY RANGE COLUMNS(joined) (
    /*PARTITION y2013 VALUES LESS THAN ('2014-01-01'),
    PARTITION y2014 VALUES LESS THAN ('2015-01-01'),
    PARTITION y2015 VALUES LESS THAN ('2016-01-01'),
    PARTITION y2016 VALUES LESS THAN ('2017-01-01'),*/ #This are older partition it may deleted before 2017 itself
    PARTITION y2017 VALUES LESS THAN ('2018-01-01'),
    PARTITION future VALUES LESS THAN MAXVALUE
);

第 2 步: 您可以使用任何编程语言,如 PHP、Ruby、Python、Perl 来动态创建此查询。假设这是 运行ning 在 2019 年 1 月 1 日使用 cron。

ALTER TABLE members 
    DROP PARTITION y2017;
ALTER TABLE members 
    REORGANIZE PARTITION future INTO
        y2018 VALUES LESS THAN ('2019-01-01'),
        future VALUES LESS THAN MAXVALUE;

查询以获取前几年的格式:

SELECT concat('Y', YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))) as prev_year

更改间隔以增加年份。

第 3 步: 使用 cron 等任何调度程序,每年执行一次上述查询。例如

@yearly /home/meenu/ubuntu/bin/annual-maintenance.sh

参考资料:

有关分区的更多信息:

  1. Create table partitioning

  2. Partitioning official document

  3. Partitioning range

Cron:

  1. Cron examples with explanation

  2. Running MySQL query periodically

大删除:

  1. Big deletes various alternatives

分区维护:

  1. Partition Maintenance