By all means, partition by unixtime. Why ???
- You can separate data by day
- You can archive the data of the oldest partition
- This can be scheduled in the MySQL event scheduler for
- adding new partitions
- deleting old partitions
- You drop the data of the oldest partition by DDL (
ALTER TABLE tbalename DROP PARTITION partitionname
) instead of DML (DELETE FROM tablename WHERE unixtime ...
). See my answer to this post Partitioning and freeing disk space
- If you are using MySQL 5.6, you can query against the specific partition instead of whole table.
Here is what I am going to do for you
Let say your table is as you gave as an example
USE mydatabase
CREATE TABLE mytable
(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
value DOUBLE NOT NULL,
device_id SMALLINT NOT NULL,
unixtime INT UNSIGNED,
PRIMARY KEY (id,unixtime),
KEY device_id (device_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY RANGE (UNIX_TIMESTAMP(unixtime))
(PARTITION p2015_05_09 VALUES LESS THAN (1431230400) ENGINE = InnoDB,
PARTITION p2015_05_10 VALUES LESS THAN (1431316800) ENGINE = InnoDB,
PARTITION p2015_05_11 VALUES LESS THAN (1431403200) ENGINE = InnoDB,
PARTITION p2015_05_12 VALUES LESS THAN (1431489600) ENGINE = InnoDB,
PARTITION p2015_05_13 VALUES LESS THAN (1431576000) ENGINE = InnoDB,
PARTITION p2015_05_14 VALUES LESS THAN (1431662400) ENGINE = InnoDB,
PARTITION p2015_05_15 VALUES LESS THAN (1431748800) ENGINE = InnoDB,
PARTITION p2015_05_16 VALUES LESS THAN (1431835200) ENGINE = InnoDB,
PARTITION p2015_05_17 VALUES LESS THAN (1431921600) ENGINE = InnoDB,
PARTITION p2015_05_18 VALUES LESS THAN (1432008000) ENGINE = InnoDB,
PARTITION p2015_05_19 VALUES LESS THAN (1432094400) ENGINE = InnoDB,
PARTITION p2015_05_20 VALUES LESS THAN (1432180800) ENGINE = InnoDB,
PARTITION p2015_05_21 VALUES LESS THAN (1432267200) ENGINE = InnoDB,
PARTITION p2015_05_22 VALUES LESS THAN (1432353600) ENGINE = InnoDB,
PARTITION p2015_05_23 VALUES LESS THAN (1432440000) ENGINE = InnoDB,
PARTITION p2015_05_24 VALUES LESS THAN (1432526400) ENGINE = InnoDB,
PARTITION p2015_05_25 VALUES LESS THAN (1432612800) ENGINE = InnoDB,
PARTITION p2015_05_26 VALUES LESS THAN (1432699200) ENGINE = InnoDB,
PARTITION p2015_05_27 VALUES LESS THAN (1432785600) ENGINE = InnoDB,
PARTITION p2015_05_28 VALUES LESS THAN (1432872000) ENGINE = InnoDB,
PARTITION p2015_05_29 VALUES LESS THAN (1432958400) ENGINE = InnoDB,
PARTITION p2015_05_30 VALUES LESS THAN (1433044800) ENGINE = InnoDB,
PARTITION p2015_05_31 VALUES LESS THAN (1433131200) ENGINE = InnoDB,
PARTITION p2015_06_01 VALUES LESS THAN (1433217600) ENGINE = InnoDB,
PARTITION p2015_06_02 VALUES LESS THAN (1433304000) ENGINE = InnoDB,
PARTITION p2015_06_03 VALUES LESS THAN (1433390400) ENGINE = InnoDB,
PARTITION p2015_06_04 VALUES LESS THAN (1433476800) ENGINE = InnoDB,
PARTITION p2015_06_05 VALUES LESS THAN (1433563200) ENGINE = InnoDB,
PARTITION p2015_06_06 VALUES LESS THAN (1433649600) ENGINE = InnoDB,
PARTITION p2015_06_07 VALUES LESS THAN (1433736000) ENGINE = InnoDB,
PARTITION p2015_06_08 VALUES LESS THAN (1433822400) ENGINE = InnoDB,
PARTITION p2015_06_09 VALUES LESS THAN (1433908800) ENGINE = InnoDB,
PARTITION p2015_06_10 VALUES LESS THAN (1433995200) ENGINE = InnoDB,
PARTITION p2015_06_11 VALUES LESS THAN (1434081600) ENGINE = InnoDB,
PARTITION p2015_06_12 VALUES LESS THAN (1434168000) ENGINE = InnoDB,
PARTITION p2015_06_13 VALUES LESS THAN (1434254400) ENGINE = InnoDB,
PARTITION p2015_06_14 VALUES LESS THAN (1434340800) ENGINE = InnoDB,
PARTITION p2015_06_15 VALUES LESS THAN (1434427200) ENGINE = InnoDB,
PARTITION p2015_06_16 VALUES LESS THAN (1434513600) ENGINE = InnoDB,
PARTITION p2015_06_17 VALUES LESS THAN (1434600000) ENGINE = InnoDB,
PARTITION p2015_06_18 VALUES LESS THAN (1434686400) ENGINE = InnoDB,
PARTITION p9999999999 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
Please note that
unixtime
must be part of the PRIMARY KEY
.
unixtime
should be INT UNSIGNED
instead of BIGINT
This will make your table 30 days back and 10 days ahead. Of course, those extra 10 days should be empty all the time.
If you run the following code, this will create the stored procedures and events that will run every night
USE yourdatabase
DELIMITER $$
DROP PROCEDURE IF EXISTS `sp_Partition_Table_Append` $$
CREATE PROCEDURE `sp_Partition_Table_Append`(
TargetDB VARCHAR(64),
TargetTB VARCHAR(64)
)
BEGIN
DECLARE Target_DBTB,pname VARCHAR(1024);
SET Target_DBTB = CONCAT(TargetDB,'.',TargetTB);
SET @dt1 = DATE(NOW()) - INTERVAL 7 DAY;
SET @looking_for_opendate = 1;
WHILE @looking_for_opendate = 1 DO
SET @dt1 = @dt1 + INTERVAL 1 DAY;
SET @dt2 = @dt1 + INTERVAL 1 DAY;
SET pname = CONCAT('p',LCASE(LEFT(DATE_FORMAT(@dt1,'%Y_%m_%d'),11)));
SELECT COUNT(1) INTO @looking_for_opendate
FROM information_schema.partitions
WHERE table_schema = TargetDB
AND table_name = TargetTB
AND partition_name = pname;
END WHILE;
SET @sql = CONCAT('ALTER TABLE ',Target_DBTB,' DROP PARTITION p9999999999');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = CONCAT('ALTER TABLE ',Target_DBTB,' ADD PARTITION (PARTITION ',pname,' VALUES LESS THAN ( UNIX_TIMESTAMP(',QUOTE(@dt2),') ) ENGINE=InnoDB)');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = CONCAT('ALTER TABLE ',Target_DBTB,' ADD PARTITION (PARTITION p9999999999 VALUES LESS THAN (MAXVALUE) ENGINE=InnoDB)');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = CONCAT('FLUSH TABLES ',Target_DBTB);
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
END $$
DELIMITER ;
DELIMITER $$
DROP PROCEDURE IF EXISTS `sp_Partition_Table_Rotate` $$
CREATE PROCEDURE `sp_Partition_Table_Rotate`(
TargetDB VARCHAR(64),
TargetTB VARCHAR(64),
DaysToKeep INT
)
ThisStoredProcedure:BEGIN
DECLARE Target_DBTB,OldPartitionToKeep,partitions_to_drop VARCHAR(1024);
DECLARE FirstOfTheMonth,OldestMonthToKeep DATE;
SET Target_DBTB = CONCAT(TargetDB,'.',TargetTB);
SET @today = DATE(NOW());
SET @oldest = @today - INTERVAL DaysToKeep DAY;
SET OldPartitionToKeep = CONCAT('p',LCASE(LEFT(DATE_FORMAT(@oldest,'%Y_%m_%d'),11)));
SELECT COUNT(1) INTO @zapcount
FROM information_schema.partitions
WHERE table_schema = TargetDB
AND table_name = TargetTB
AND partition_name < OldPartitionToKeep;
IF @zapcount = 0 THEN LEAVE ThisStoredProcedure; END IF;
SELECT GROUP_CONCAT(partition_name) INTO partitions_to_drop
FROM information_schema.partitions
WHERE table_schema = TargetDB
AND table_name = TargetTB
AND partition_name < OldPartitionToKeep;
SET @sql = CONCAT('ALTER TABLE ',Target_DBTB,' DROP PARTITION ',partitions_to_drop);
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
END $$
DELIMITER ;
DELIMITER $$
DROP EVENT IF EXISTS Append_Daily_Partitions $$
CREATE EVENT Append_Daily_Partitions
ON SCHEDULE
EVERY 1 DAY
STARTS DATE(NOW() + INTERVAL 1 DAY) - INTERVAL 15 MINUTE
ON COMPLETION PRESERVE
DO
ThisScheduledEvent:BEGIN
DECLARE srcdb,srctb VARCHAR(64);
DECLARE FoundCount INT;
SET srcdb = DATABASE();
DROP TABLE IF EXISTS PartitionedTablesToRotate;
CREATE TABLE PartitionedTablesToRotate
(
id INT NOT NULL AUTO_INCREMENT,
table_schema VARCHAR(64) NOT NULL,
table_name VARCHAR(64) NOT NULL,
days_to_retain INT NOT NULL DEFAULT 30,
PRIMARY KEY (id),
UNIQUE KEY DB_TBL_INDEX (table_schema,table_name)
);
INSERT INTO PartitionedTablesToRotate
(table_schema,table_name)
SELECT table_schema,table_name
FROM information_schema.partitions
WHERE table_schema=srcdb
AND partition_name='p9999999999';
SET @ndx = 0;
SELECT COUNT(1) INTO @lastndx FROM PartitionedTablesToRotate;
WHILE @ndx < @lastndx DO
SET @ndx = @ndx + 1;
SELECT table_name INTO srctb
FROM PartitionedTablesToRotate WHERE id = @ndx;
SELECT COUNT(1) INTO FoundCount
FROM information_schema.partitions
WHERE table_schema = srcdb
AND table_name = srctb
AND partition_name = 'p9999999999';
IF FoundCount = 1 THEN
CALL sp_Partition_Table_Append(srcdb,srctb);
END IF;
END WHILE;
END $$
DELIMITER ;
DELIMITER $$
DROP EVENT IF EXISTS Rotate_Daily_Partitions $$
CREATE EVENT Rotate_Daily_Partitions
ON SCHEDULE
EVERY 1 DAY
STARTS DATE(NOW() + INTERVAL 1 DAY) + INTERVAL 15 MINUTE
ON COMPLETION PRESERVE
DO
ThisScheduledEvent:BEGIN
DECLARE srcdb,srctb VARCHAR(64);
DECLARE FoundCount,DaysToKeep INT;
SET srcdb = DATABASE();
SELECT COUNT(1) INTO FoundCount FROM information_schema.tables
WHERE table_schema=srcdb AND table_name='PartitionedTablesToRotate';
IF FoundCount = 0 THEN
LEAVE ThisScheduledEvent;
END IF;
SET @ndx = 0;
SELECT COUNT(1) INTO @lastndx FROM PartitionedTablesToRotate;
WHILE @ndx < @lastndx DO
SET @ndx = @ndx + 1;
SELECT table_name,days_to_retain INTO srctb,DaysToKeep
FROM PartitionedTablesToRotate WHERE id = @ndx;
SELECT COUNT(1) INTO FoundCount
FROM information_schema.partitions
WHERE table_schema = srcdb
AND table_name = srctb
AND partition_name = 'p9999999999';
IF FoundCount = 1 THEN
CALL sp_Partition_Table_Rotate(srcdb,srctb,DaysToKeep);
END IF;
END WHILE;
END $$
DELIMITER ;
DELIMITER $$
SET GLOBAL event_scheduler = 'ON';
The events will do the following:
Append_Daily_Partitions
will add new partition at 11:45 PM
Rotate_Daily_Partitions
will delete old partition at 12:15 AM
Please install this on a Dev or Staging Server and verify to works for you.
GIVE IT A TRY !!!