You are here

Hacking to make ALTER TABLE online for certain changes

MySQL Performance Blog - Mon, 29/10/2007 - 12:49pm

Suppose you want to remove auto_increment from 100G table. No matter if it's InnoDB or MyISAM, you'd usually ALTER TABLE `huge_table` CHANGE `id` `id` int(6) NOT NULL and then wait hours for table rebuild to complete. If you're unlucky i.e. you have a lot of indexes and not too much RAM - you could end up waiting days. If you want to make this happen quick - there's another way. Not documented, but works well with both - InnoDB and MyISAM.

Now that more and more folks hit the InnoDB auto-inc scalability issue with MySQL 5.0 and older versions, employing other techniques to maintain the PK auto incremental becomes more of an issue. One of the steps here is to remove current PK auto_incremental from the table. As a rule of thumb, this usually involves altering huge InnoDB tables and huge tables take time to rebuild.

Disclaimer: try this at your own risk. It worked for me, it may work for you too, but always have a backup before doing that kind of stuff, as it is not the way MySQL would advice you to do it and we can't guarantee it will work well for you either.

So, in a nutshell, all you have to do is create another table with desired table structure and switch .frm table definition files. For safety, I'd recommend to flush tables with read lock while switching .frm files. When and how it works:

auto_increment (removing). Let's have a simple table with auto_increment we want to get rid of:

  1. CREATE TABLE `huge_table` (
  2.   `id` int(6) NOT NULL AUTO_INCREMENT,
  3.   `text` text NOT NULL,
  4.   PRIMARY KEY  (`id`)
  5. ) ENGINE=InnoDB

To remove auto_increment, we (1) create table with the same layout but without auto_increment, (2) flush tables with read lock, (3) swap .frm files while keeping mysql suspended and (4) unlock the tables afterwards:

  1. -- 1.
  2. mysql> CREATE TABLE `huge_table_new` (
  3. ->   `id` int(6) NOT NULL,
  4. ->   `text` text NOT NULL,
  5. ->   PRIMARY KEY  (`id`)
  6. -> ) ENGINE=INNODB;
  7. Query OK, 0 rows affected (0.01 sec)
  9. -- 2.
  11. Query OK, 0 rows affected (0.00 sec)
  13. -- 3.
  14. mysql> ^Z
  15. [1]+  Stopped                 mysql test
  16. # mv huge_table.frm huge_table_old.frm && mv huge_table_new.frm huge_table.frm && mv huge_table_old.frm huge_table_new.frm
  17. # fg
  18. mysql test
  19. -- 4.
  20. mysql> UNLOCK TABLES;
  21. Query OK, 0 rows affected (0.00 sec)
  23. mysql> SHOW CREATE TABLE `huge_table`\G
  24. *************************** 1. row ***************************
  25. TABLE: huge_table
  26. CREATE TABLE: CREATE TABLE `huge_table` (
  27.   `id` int(6) NOT NULL,
  28.   `text` text NOT NULL,
  29.   PRIMARY KEY  (`id`)
  31. 1 row IN SET (0.00 sec)
  33. mysql> INSERT INTO `huge_table` (text) VALUES ('test');
  34. ERROR 1062 (23000): Duplicate entry '0' FOR KEY 1

Unfortunately, adding auto_increment does not work that way.

Enum values (add and remove). Enumerated values are added and removed the same way that auto_increment is removed. I've been a bit surprised, that removing value from enum() works as good as adding it - rows that have incorrect values are just returned as empty. But I suppose this does violate mysql data file structure, so be really careful with that one.

Default values. MySQL rebuilds table even if we only want to change the default value for new records so this may save one from a lot of trouble.

Table comment. I'm pretty sure that would work for changing table comment as well, however - changing a comment with a help of ALTER TABLE does not rebuild the table, so we better use the documented method for that.

What I'm surprised about is that changing a comment does not to require table to be rebuilt, while things like removing auto_increment or changing a default value still do even though this information is stored in table definition file.

If you'll ever try this, please leave a comment if it did work for you. Maybe you have discovered some new things to alter that way?

Entry posted by Aurimas | No comment

Add to: delicious | digg | reddit | netscape | Google Bookmarks