[Zabbix] DB 파티셔닝 (MySQL)

DB 파티셔닝

Housekeeper는 Zabbix에서 사용되는 개념으로 Zabbix에서 데이터를 수집하게 되면 사용자가 설정한 기간만큼 데이터를 보관한다. 보관기간이 지나면 보관 기간이 지난 데이터를 삭제하게되는데 삭제해주는 역할을 하는 프로세스가 Housekeeper이다. Housekeeper는 평소에는 프로세스를 점유하고 있지 않다가 데이터를 삭제할 때만 100%로 프로세스를 점유하여 동작한다.

관련된 값은 zabbix_server.conf에서 튜닝해서 사용할 수 있고 관련된 파라미터 값은 다음과 같다.

  • HousekeepingFrequency (0-24h) (Default : 1) : Housekeeper를 실행할 주기를 설정한다.
  • MaxHousekeeperDelete (0-1000000) (Default : 5000) : Housekeeper가 최대로 삭제할 수 있는 데이터수를 설정한다. 만약, 0일 경우 삭제할 수 있는 제한이 사라지게 된다. (이는 DB에 과부하가 가해질 수 있음)

Housekeeper는 데이터 삭제를 삭제할 때 SQL DELETE를 사용하여 삭제하기 때문에 삭제할 데이터가 많을경우 Zabbix DB성능저하에 많은 영향을 미친다. 이를 해소하기 위해서 테이블 파티셔닝을 진행한다.

파티셔닝을 하게될 경우 매일 일별의 테이블을 만들고 데이터의 삭제기한이 다가왔을 때 SQL DROP으로 테이블을 삭제하기 때문에 훨씬 효율적이다.

Housekeeper 프로세스 점유에 대해 Slack 알람이 온 상황

https://www.zabbix.org/wiki/Docs/howto/MySQLTable_Partitioning(variant) 공식 홈페이지에서 제공하는 MySQL Table 파티셔닝 관련내용이다. 해당 글을 참고해서 진행한다.

파티셔닝 Zabbix 서버환경

  • MySQL - 5.7.33
    • 공식 Document에서는 MySQL5.6 이상을 권장한다.
  • Zabbix Server - 5.2.5

DB 파티셔닝 전 확인사항

  1. Event_Scheduler ON 확인

    mysql -u root -p
    mysql> SHOW GLOBAL VARIABLES LIKE 'event_scheduler';
    +-----------------+-------+
    | Variable_name   | Value |
    +-----------------+-------+
    | event_scheduler | OFF   |
    +-----------------+-------+
    1 row in set (0.00 sec)
    
    mysql>  SET GLOBAL event_scheduler = ON;
    Query OK, 0 rows affected (0.00 sec)
    • 위의 MySQL 명령어는 일시적용이므로 영구적용 시 DB의 'my.cnf' 파일에 event_scheduler=ON 문구 추가필요
  2. Table의 최소 Clock 단위 확인

    mysql> use zabbix;
    mysql> SELECT FROM_UNIXTIME(MIN(clock)) FROM `history_uint`;
    +---------------------------+
    | FROM_UNIXTIME(MIN(clock)) |
    +---------------------------+
    | 2021-03-23 11:50:24       |
    +---------------------------+
    1 row in set (5.83 sec)
    • 모든 테이블에 대해 Clock 필드의 최소 값부터 파티션을 분할할 테이블의 현재 순간까지 파티션을 지정해야 한다.

테이블 파티셔닝

각각의 테이블에 기록되어있는 데이터 생성의 최소 날짜부터 현재날짜까지의 테이블을 수동으로 파티셔닝한다. 만약 데이터 생성의 최소 날짜가 21년 3월 1일이라면 3월부터 현재날짜에서 +1일 까지 수동으로 파티셔닝을 추가해줘야 한다.

*현재날짜에서 +1일까지 파티셔닝하지 않는다면 ERROR 1526 (HY000): Table has no partition for value... 라는 에러메시지를 보게될 것이다.

Daily partitioning에 해당하는 테이블들은 하루 기준으로 파티셔닝이 진행되어야 하고 Monthly partitioning에 해당하는 테이블들은 한달 기준으로 파티셔닝이 진행되어야 한다.

일별 파티셔닝

일별로 파티셔닝 해야할 테이블 목록

  • history
  • history_log
  • history_str
  • history_text
  • history_uint
  1. 각각의 테이블에 기록되어있는 데이터 생성의 최소 날짜 확인

    • 출력된 날짜를 기준으로 현재날짜 +1일 까지 파티셔닝을 한다.
    SELECT FROM_UNIXTIME(MIN(clock)) FROM `history`;
    SELECT FROM_UNIXTIME(MIN(clock)) FROM `history_log`;
    SELECT FROM_UNIXTIME(MIN(clock)) FROM `history_str`;
    SELECT FROM_UNIXTIME(MIN(clock)) FROM `history_text`;
    SELECT FROM_UNIXTIME(MIN(clock)) FROM `history_uint`;

    각각의 테이블의 이전의 모든 데이터를 보존하려면 일별로 파티셔닝 해야하지만 그럴필요가 없고 귀찮기도 하면 기간을 한달, 1년 혹은 이전부터 현재까지 통으로 파티닝해도 된다.

  2. 일별 파티셔닝 진행

    ALTER TABLE `history` PARTITION BY RANGE (clock)
    (PARTITION p2021_01_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-07 00:00:00")) ENGINE = InnoDB,
    ... # 중략
     PARTITION p2021_06_17 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-18 00:00:00")) ENGINE = InnoDB);
    
    ALTER TABLE `history_log` PARTITION BY RANGE (clock)
    (PARTITION p2021_01_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-07 00:00:00")) ENGINE = InnoDB,
    ... # 중략
     PARTITION p2021_06_17 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-18 00:00:00")) ENGINE = InnoDB);
    
    ALTER TABLE `history_str` PARTITION BY RANGE (clock)
    (PARTITION p2021_01_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-07 00:00:00")) ENGINE = InnoDB,
    ... # 중략
     PARTITION p2021_06_17 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-18 00:00:00")) ENGINE = InnoDB);
    
    ALTER TABLE `history_text` PARTITION BY RANGE (clock)
    (PARTITION p2021_01_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-07 00:00:00")) ENGINE = InnoDB,
    ... # 중략
     PARTITION p2021_06_17 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-18 00:00:00")) ENGINE = InnoDB);
    
    ALTER TABLE `history_uint` PARTITION BY RANGE (clock)
    (PARTITION p2021_01_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-07 00:00:00")) ENGINE = InnoDB,
    ... # 중략
     PARTITION p2021_06_17 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-18 00:00:00")) ENGINE = InnoDB);
    • 실제 명령어

*history의 용량이 너무 비대하면 파티셔닝에 오래걸릴 수 있음.

월별 파티셔닝

월별로 파티셔닝 해야할 테이블 목록

  • trends
  • trends_uint
  1. 각각의 테이블에 기록되어있는 데이터 생성의 최소 날짜 확인

    SELECT FROM_UNIXTIME(MIN(clock)) FROM `trends`;
    SELECT FROM_UNIXTIME(MIN(clock)) FROM `trends_uint`;
  2. 월별 파티셔닝 진행

    ALTER TABLE `trends` PARTITION BY RANGE (clock)
    (PARTITION p2020_11 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2020_12 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_01 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_02 VALUES LESS THAN (UNIX_TIMESTAMP("2021-03-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_03 VALUES LESS THAN (UNIX_TIMESTAMP("2021-04-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_04 VALUES LESS THAN (UNIX_TIMESTAMP("2021-05-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_05 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-07-01 00:00:00")) ENGINE = InnoDB);
    
    ALTER TABLE `trends_uint` PARTITION BY RANGE (clock)
    (PARTITION p2020_11 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2020_12 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_01 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_02 VALUES LESS THAN (UNIX_TIMESTAMP("2021-03-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_03 VALUES LESS THAN (UNIX_TIMESTAMP("2021-04-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_04 VALUES LESS THAN (UNIX_TIMESTAMP("2021-05-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_05 VALUES LESS THAN (UNIX_TIMESTAMP("2021-06-01 00:00:00")) ENGINE = InnoDB,
     PARTITION p2021_06 VALUES LESS THAN (UNIX_TIMESTAMP("2021-07-01 00:00:00")) ENGINE = InnoDB);

파티셔닝 프로시저 생성 및 EVENT 등록

DB 파티셔닝에는 스크립트 방식과 프로시저 방식이 있는데 여기서는 프로시저 방식으로 진행한다.

  1. 파티셔닝 테이블을 관리하는 manage_partitions 테이블 생성

    # 파티셔닝 테이블 생성 1
    CREATE TABLE IF NOT EXISTS `manage_partitions` (
      `tablename` VARCHAR(64) NOT NULL COMMENT 'Table name',
      `period` VARCHAR(64) NOT NULL COMMENT 'Period - daily or monthly',
      `keep_history` INT(3) UNSIGNED NOT NULL DEFAULT '1' COMMENT 'For how many days or months to keep the partitions',
      `last_updated` DATETIME DEFAULT NULL COMMENT 'When a partition was added last time',
      `comments` VARCHAR(128) DEFAULT '1' COMMENT 'Comments',
      PRIMARY KEY (`tablename`)
    ) ENGINE=INNODB;
    
    # 파티셔닝 테이블 생성 2
    CREATE TABLE IF NOT EXISTS `manage_partitions_history` (
      `schema_name` varchar(64) NOT NULL COMMENT 'Zabbix schema name',
      `table_name` varchar(64) NOT NULL COMMENT 'Zabbix table name',
      `table_partition_name` varchar(64) NOT NULL COMMENT 'Zabbix table partition name',
      `partition_action` varchar(64) NOT NULL COMMENT 'Zabbix table partition action',
      `partition_action_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'When a partition was added or dropped'
    ) ENGINE=InnoDB;
  2. 생성한 테이블에 컬럼추가

    # 생성한 파티션 테이블에 컬럼 추가
    # 데이터를 유지할 기간을 사용자 환경에 맞춰서 설정한다.
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('history', 'day', 90, now(), '');
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('history_uint', 'day', 90, now(), '');
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('history_str', 'day', 90, now(), '');
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('history_text', 'day', 90, now(), '');
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('history_log', 'day', 90, now(), '');
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('trends', 'month', 12, now(), '');
    INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES ('trends_uint', 'month', 12, now(), '');
  3. 파티션을 생성하고 삭제하는 프로시저 생성

    # 파티션을 생성하는 프로시저를 생성
    DELIMITER $$
    CREATE PROCEDURE `create_next_partitions`(IN_SCHEMANAME VARCHAR(64))
    BEGIN
        DECLARE TABLENAME_TMP VARCHAR(64);
        DECLARE PERIOD_TMP VARCHAR(12);
        DECLARE DONE INT DEFAULT 0;
        DECLARE get_prt_tables CURSOR FOR
            SELECT `tablename`, `period`
            FROM manage_partitions;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
        OPEN get_prt_tables;
            loop_create_part: LOOP
                IF DONE THEN
                    LEAVE loop_create_part;
                END IF;
                FETCH get_prt_tables INTO TABLENAME_TMP, PERIOD_TMP;
                CASE 
                    WHEN PERIOD_TMP = 'day' THEN
                        CALL `create_partition_by_day`(IN_SCHEMANAME, TABLENAME_TMP);
                    WHEN PERIOD_TMP = 'month' THEN
                        CALL `create_partition_by_month`(IN_SCHEMANAME, TABLENAME_TMP);
                    ELSE
                    BEGIN
                        ITERATE loop_create_part;
                    END;
                END CASE;
                    UPDATE manage_partitions set last_updated = NOW() WHERE tablename = TABLENAME_TMP;
            END LOOP loop_create_part;
        CLOSE get_prt_tables;
    END$$
    DELIMITER ;
    
    # 일별의 파티션을 생성하는 프로시저 생성
    DELIMITER $$
    CREATE PROCEDURE `create_partition_by_day`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
    BEGIN
        DECLARE BEGINTIME TIMESTAMP;
        DECLARE ENDTIME INT UNSIGNED;
        DECLARE PART_ACTION VARCHAR(12);
        DECLARE PARTITIONNAME VARCHAR(16);
        DECLARE ROWS_CNT INT UNSIGNED;
        SET BEGINTIME = DATE(NOW()) + INTERVAL 1 DAY;
        SET ENDTIME = UNIX_TIMESTAMP(BEGINTIME + INTERVAL 1 DAY + INTERVAL 9 HOUR);
        SET PART_ACTION = 'ADD';
        SET PARTITIONNAME = DATE_FORMAT( BEGINTIME, 'p%Y_%m_%d' );
        SELECT COUNT(*) INTO ROWS_CNT
        FROM information_schema.partitions
        WHERE table_schema = IN_SCHEMANAME 
            AND table_name = IN_TABLENAME 
            AND partition_name = PARTITIONNAME;
        IF ROWS_CNT = 0 THEN
            SET @SQL = CONCAT('INSERT INTO `manage_partitions_history`(`schema_name`,`table_name`,`table_partition_name`,`partition_action`) VALUES ("', IN_SCHEMANAME,'","', IN_TABLENAME,'","', PARTITIONNAME,'","', PART_ACTION,'");');
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
            SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', ENDTIME, '));' );
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
            ELSE
                SELECT CONCAT("partition `", PARTITIONNAME, "` for table `",IN_SCHEMANAME, ".", IN_TABLENAME, "` already exists") AS result;
        END IF;
    END$$
    DELIMITER ;
    
    # 월별의 파티션을 생성하는 프로시저 생성
    DELIMITER $$
    CREATE PROCEDURE `create_partition_by_month`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
    BEGIN
        DECLARE BEGINTIME TIMESTAMP;
        DECLARE ENDTIME INT UNSIGNED;
        DECLARE PART_ACTION VARCHAR(12);
        DECLARE PARTITIONNAME VARCHAR(16);
        DECLARE ROWS_CNT INT UNSIGNED;
        SET BEGINTIME = DATE(NOW() - INTERVAL DAY(NOW()) DAY + INTERVAL 1 DAY + INTERVAL 1 MONTH);
        SET ENDTIME = UNIX_TIMESTAMP(BEGINTIME + INTERVAL 1 MONTH + INTERVAL 9 HOUR);
        SET PART_ACTION = 'ADD';
        SET PARTITIONNAME = DATE_FORMAT( BEGINTIME, 'p%Y_%m' );
        SELECT COUNT(*) INTO ROWS_CNT
        FROM information_schema.partitions
        WHERE table_schema = IN_SCHEMANAME 
            AND table_name = IN_TABLENAME 
            AND partition_name = PARTITIONNAME;
        IF ROWS_CNT = 0 THEN
            SET @SQL = CONCAT('INSERT INTO `manage_partitions_history`(`schema_name`,`table_name`,`table_partition_name`,`partition_action`) VALUES ("', IN_SCHEMANAME,'","', IN_TABLENAME,'","', PARTITIONNAME,'","', PART_ACTION,'");');
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
            SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', ENDTIME, '));' );
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
            ELSE
                SELECT CONCAT("partition `", PARTITIONNAME, "` for table `",IN_SCHEMANAME, ".", IN_TABLENAME, "` already exists") AS result;
        END IF;
    END$$
    DELIMITER ;
    
    # 오래된 파티션을 삭제하는 프로시저 생성
    DELIMITER $$
    CREATE PROCEDURE `drop_partitions`(IN_SCHEMANAME VARCHAR(64))
    BEGIN
        DECLARE TABLENAME_TMP VARCHAR(64);
        DECLARE PARTITIONNAME_TMP VARCHAR(64);
        DECLARE VALUES_LESS_TMP INT;
        DECLARE PERIOD_TMP VARCHAR(12);
        DECLARE KEEP_HISTORY_TMP INT;
        DECLARE KEEP_HISTORY_BEFORE INT;
        DECLARE DONE INT DEFAULT 0;
        DECLARE get_partitions CURSOR FOR
            SELECT p.`table_name`, p.`partition_name`, LTRIM(RTRIM(p.`partition_description`)), mp.`period`, mp.`keep_history`
            FROM information_schema.partitions p
            JOIN manage_partitions mp ON mp.tablename = p.table_name
            WHERE p.table_schema = IN_SCHEMANAME
            ORDER BY p.table_name, p.subpartition_ordinal_position;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
        OPEN get_partitions;
            loop_check_prt: LOOP
                IF DONE THEN
                    LEAVE loop_check_prt;
                END IF;
                FETCH get_partitions INTO TABLENAME_TMP, PARTITIONNAME_TMP, VALUES_LESS_TMP, PERIOD_TMP, KEEP_HISTORY_TMP;
                CASE 
                    WHEN PERIOD_TMP = 'day' THEN
                        SET KEEP_HISTORY_BEFORE = UNIX_TIMESTAMP(DATE(NOW() - INTERVAL KEEP_HISTORY_TMP DAY) + INTERVAL 9 HOUR);
                    WHEN PERIOD_TMP = 'month' THEN
                        SET KEEP_HISTORY_BEFORE = UNIX_TIMESTAMP(DATE(NOW() - INTERVAL KEEP_HISTORY_TMP MONTH - INTERVAL DAY(NOW())-1 DAY) + INTERVAL 9 HOUR);
                    ELSE
                        BEGIN
                            ITERATE loop_check_prt;
                        END;
                END CASE;
                IF KEEP_HISTORY_BEFORE >= VALUES_LESS_TMP THEN
                    CALL drop_old_partition(IN_SCHEMANAME, TABLENAME_TMP, PARTITIONNAME_TMP);
                END IF;
            END LOOP loop_check_prt;
        CLOSE get_partitions;
    END$$
    DELIMITER ;
    
    # 오래된 파티션 삭제
    DELIMITER $$
    CREATE PROCEDURE `drop_old_partition`(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64), IN_PARTITIONNAME VARCHAR(64))
    BEGIN
        DECLARE PART_ACTION VARCHAR(12);
        DECLARE PART_ACTION_DATE INT;
        DECLARE ROWS_CNT INT UNSIGNED;
            SELECT COUNT(*) INTO ROWS_CNT
            FROM information_schema.partitions
            WHERE table_schema = IN_SCHEMANAME 
                AND table_name = IN_TABLENAME 
                AND partition_name = IN_PARTITIONNAME;
        SET PART_ACTION = 'DROP';
        IF ROWS_CNT = 1 THEN
            SET @SQL = CONCAT('INSERT INTO `manage_partitions_history`(`schema_name`,`table_name`,`table_partition_name`,`partition_action`) VALUES ("', IN_SCHEMANAME,'","', IN_TABLENAME,'","', IN_PARTITIONNAME,'","', PART_ACTION,'");');
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
            SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',' DROP PARTITION ', IN_PARTITIONNAME, ';' );
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
            ELSE
                SELECT CONCAT("partition `", IN_PARTITIONNAME, "` for table `", IN_SCHEMANAME, ".", IN_TABLENAME, "` does not exist") AS result;
        END IF;
    END$$
    DELIMITER ;
  4. 파티셔닝을 관리하는 Event 생성

    # 테이블 파티셔닝 작업예약(Event)
    # Housekeeper대신 매일 파티셔닝을 수동으로 수행한다.
    DELIMITER $$
    CREATE EVENT `e_zbx_part_mgmt` 
        ON SCHEDULE EVERY 1 DAY STARTS '2021-06-18 00:00:00' 
        ON COMPLETION PRESERVE 
        ENABLE 
        COMMENT 'Creating and dropping partitions' 
        DO BEGIN
            CALL zabbix.drop_partitions('zabbix');
            CALL zabbix.create_next_partitions('zabbix');
        END$$
    DELIMITER ;

Housekeeper 비 활성화

테이블 파티셔닝을 예약 했으니 이제 Housekeeper를 비활성화 시킨다.

  • Zabbix Web의 'Administrators'→ 'General' → 'Housekeeping'
  • 원하는 기간 기입
  • 위와 같이 설정할 경우 History는 90일치의 데이터만 보관될것이고 Trends는 365일치의 데이터만 보관될 것이다.

파티셔닝 확인

이제 파티셔닝이 잘 되었는지 확인해보자.

  1. Event 확인

    • 등록한 Event 확인
    mysql> use zabbix;
    mysql> show events\G
    *************************** 1. row ***************************
                      Db: zabbix
                    Name: e_zbx_part_mgmt
                 Definer: root@localhost
               Time zone: SYSTEM
                    Type: RECURRING
              Execute at: NULL
          Interval value: 1
          Interval field: DAY
                  Starts: 2021-06-18 00:00:00
                    Ends: NULL
                  Status: ENABLED
              Originator: 1
    character_set_client: utf8mb4
    collation_connection: utf8mb4_general_ci
      Database Collation: utf8_bin
    1 row in set (0.001 sec)
  2. Event 기록 확인

    • Event가 설정한 시간대에 동작하는지 확인
    • 특히 LAST_EXECUTED의 시간을 확인해서 다음날 00시에 실행되는지 확인한다.
    mysql> SELECT * FROM INFORMATION_SCHEMA.events\G
    *************************** 1. row ***************************
           EVENT_CATALOG: def
            EVENT_SCHEMA: zabbix
              EVENT_NAME: e_zbx_part_mgmt
                 DEFINER: root@localhost
               TIME_ZONE: SYSTEM
              EVENT_BODY: SQL
        EVENT_DEFINITION: BEGIN
            CALL zabbix.drop_partitions('zabbix');
            CALL zabbix.create_next_partitions('zabbix');
        END
              EVENT_TYPE: RECURRING
              EXECUTE_AT: NULL
          INTERVAL_VALUE: 1
          INTERVAL_FIELD: DAY
                SQL_MODE: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
                  STARTS: 2021-06-18 00:00:00
                    ENDS: NULL
                  STATUS: ENABLED
           ON_COMPLETION: PRESERVE
                 CREATED: 2021-06-17 10:11:28
            LAST_ALTERED: 2021-06-17 10:11:28
           LAST_EXECUTED: 2021-10-01 00:00:00
           EVENT_COMMENT: Creating and dropping partitions
              ORIGINATOR: 1
    CHARACTER_SET_CLIENT: utf8mb4
    COLLATION_CONNECTION: utf8mb4_general_ci
      DATABASE_COLLATION: utf8_bin
    1 row in set (0.001 sec)
  3. Table 생성 기록 확인

    • 설정된 기간이 지난 테이블을 삭제하는지, 주기적으로 테이블을 생성하는지 확인한다.
    mysql> show create table history\G
    PARTITION `p2021_08_16` VALUES LESS THAN (1629158400) ENGINE = InnoDB,
    ...
     PARTITION `p2021_10_01` VALUES LESS THAN (1633132800) ENGINE = InnoDB,
     PARTITION `p2021_10_02` VALUES LESS THAN (1633219200) ENGINE = InnoDB)
  4. 모든 파티셔닝 테이블 확인

    • 모든 파티셔닝 테이블의 CREATE_TIME, UPDATE_TIME 등을 확인한다.
    mysql> select * from information_schema.partitions where table_name = 'history'\G
  5. 파티셔닝 테이블의 실제 데이터값 확인

    • 실제 데이터값이 있는지 확인한다.
    mysql> select * from history partition (p2021_09_30);

+ 잘못 생성한 테이블 삭제

명령어를 잘못 입력해서 이상하게 생성된 테이블을 삭제한다.

  1. 잘못생성한 파티션 삭제

    mysql> alter table history drop partition p2021_03_23;
  2. ERROR 1508 (HY000): Cannot remove all partitions, use DROP TABLE instead 에러 발생 시

    # 마지막 파티션 테이블 삭제
    alter table history remove partitioning;

좋은 웹페이지 즐겨찾기