Search code examples
mysqlprimary-keypartitioningauto-increment

Modifying AUTO_INCREMENT PRIMARY KEY for partitioning


I need to partition a MySQL table amongst temporal data (field begin in the following table).

CREATE TABLE `table1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `fk_id` bigint(20) NOT NULL,  
  `begin` bigint(20) NOT NULL,     
  PRIMARY KEY (`id`),
  KEY `FK1E57078DB20EC268` (`fk_id`)
) ENGINE=MyISAM AUTO_INCREMENT=10443288 DEFAULT CHARSET=latin1

When I try to partition like this :

alter table table1 partition by range (begin) (
PARTITION until_2010_07 VALUES LESS THAN (1280620800000),
PARTITION 2010_08 VALUES LESS THAN (1283299200000),
PARTITION 2010_09 VALUES LESS THAN (1285891200000),
PARTITION 2010_10 VALUES LESS THAN (1288569600000),
PARTITION 2010_11 VALUES LESS THAN (1291161600000),
PARTITION 2010_12 VALUES LESS THAN (1293840000000),
PARTITION from_2011 VALUES LESS THAN MAXVALUE
);

I get a MySQL error : ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

As I understand from the mysql doc, a partitioning column should belongs to the primary key. The problem for me is that I want to change the PRIMARY_KEY to be a composite one ie PRIMARY KEY ('id','fk_id','begin') without changing the existing id columns (because it's a field that is used in the application to generate bookmarkable urls, so renumbering the ids is not an option)

How can I alter the PRIMARY_KEY so that I can do my partitioning ?


Solution

  • I finally found a way to do it, I answer for the sake of other people who come across this question

    //drop auto_increment capability
    alter table table1 change column id id BIGINT NOT NULL;
    //in one line, drop primary key and rebuild one
    alter table table1 drop primary key, add primary key(id,fk_id,begin);
    //re add the auto_increment capability, last value is remembered
    alter table table1 change column id id BIGINT NOT NULL AUTO_INCREMENT;
    //build the partition
    alter table table1 partition by range (begin) ( 
        PARTITION until_2010_07 VALUES LESS THAN (1280620800000), 
        PARTITION 2010_08 VALUES LESS THAN (1283299200000), 
        PARTITION 2010_09 VALUES LESS THAN (1285891200000), 
        PARTITION 2010_10 VALUES LESS THAN (1288569600000), 
        PARTITION 2010_11 VALUES LESS THAN (1291161600000), 
        PARTITION 2010_12 VALUES LESS THAN (1293840000000), 
        PARTITION from_2011 VALUES LESS THAN MAXVALUE 
    );
    

    Partitioning is indeed really easy, but I advice people to think about it while creating the primary key before actually using their database in production :-)

    Each step takes 3 minutes on my laptop, then i'll have to stop the service to keep consistency in my database