使用存储过程和事件调度程序

时间:2018-02-05 06:14:23

标签: mysql database-partitioning

我有一个表,我希望通过首先按月对表进行分区然后按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

提前致谢!

1 个答案:

答案 0 :(得分:1)

首先,分区是您遇到的问题的最佳用例。原因是您使用innodb的存储引擎是基于事务的引擎。因此,它将日志中完成的所有操作记录在更高I/O资源中。而对于删除,即使它需要更多的资源。但是使用子分区进行分区是过度的,因为您需要每年清理一次表数据,这样就可以使用RANGE COLUMN子句和cron作业,该作业每年运行一次。

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

SHOW PLUGINS;

这将显示一个表格数据,请在partition列中的name栏中查看ACTIVE Status

分区类型:

有两种类型的分区。它们是垂直分区(逐列分区),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] ...)]

<强> SOLUTION:

第1步: 使用这样的分区更改表模式(参考链接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)动态创建此查询。考虑这是在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

  4. <强>的Cron:

    1. Cron examples with explanation

    2. Running MySQL query periodically

    3. 大删除:

      1. Big deletes various alternatives
      2. 分区维护:

        1. Partition Maintenance