Tue, 09 Jan 2007

Reason 82973 why MySQL is a toy

MySQL cleverly maps

CREATE INDEX foo_bar ON Foo(Bar);

to

LOCK TABLE Foo WRITE;
CREATE TEMPORARY TABLE A-Foo ( .... INDEX foo_bar (Bar));
INSERT INTO A-Foo SELECT * FROM Foo;
ALTER TABLE Foo RENAME TO B-Foo;
ALTER TABLE A-Foo RENAME TO Foo;
DROP TABLE B-Foo;

If you have a very large table, expect this operation to take a) a lot of disk space, b) a very very long time and c) block any writes to the table in the process. I don't recommend adding indexes or altering any very large tables that are in production on MySQL, because you won't be in production for quite some time.

Update: Tom Haddon asked me if this applied to recent versions of MySQL or to PostgreSQL. Looking at the docs, it appears to still apply to 5.1:

  • http://dev.mysql.com/doc/refman/5.1/en/create-index.html
  • http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

    In some cases, no temporary table is necessary:

    • If you use ALTER TABLE tbl_name RENAME TO new_tbl_name without any other options, MySQL simply renames any files that correspond to the table tbl_name. (You can also use the RENAME TABLE statement to rename tables. See Section 13.1.16, “RENAME TABLE Syntax”.)

    • ALTER TABLE ... ADD PARTITION creates no temporary table except for MySQL Cluster. ADD or DROP operations for RANGE or LIST partitions are immediate operations or nearly so. ADD or COALESCE operations for HASH or KEY partitions copy data between changed partitions; unless LINEAR HASH/KEY was used, this is much the same as creating a new table (although the operation is done partition by partition). REORGANIZE operations copy only changed partitions and do not touch unchanged ones.

    If other cases, MySQL creates a temporary table, even if the data wouldn't strictly need to be copied (such as when you change the name of a column).

  • http://dev.mysql.com/doc/refman/5.1/en/alter-table-problems.html

As far as PostgreSQL is concerned, it doesn't mention anything about doing the same thing, but does mention that it does a full sequential scan of the table. During this time writes are blocked. You can use the CONCURRENTLY keyword to allow writes to happen, but it does two scans and will take longer, but you can still use your database.

http://www.postgresql.org/docs/8.2/interactive/sql-createindex.html

[, , ] | # Read Comments (4) |

Related Products

Comments

I guess "ALTER TABLE A-Foo RENAME TO A-Foo;" should have read "ALTER TABLE A-Foo RENAME TO Foo;".

Otherwise, what are you accusing? Speed of MyQQL?

4.1? 5.0? 5.1?
Posted by Béranger at Tue Jan 9 10:47:54 2007
Can you let me know which version of MySQL you're using and also confirm that this isn't the case in, for instance, PostgreSQL? I've always suspected avoiding MySQL was a good idea for the projects I was interested in and I'd like to have concrete proof of it...
Posted by Tom Haddon at Tue Jan 9 11:03:49 2007
On Oracle it's faster to insert into a table without indexes and then create an index afterwards. Does this also apply to your example?

Thus is the following faster?
CREATE TEMPORARY TABLE A-Foo AS SELECT * FROM Foo;
CREATE INDEX A-Foo-Idx ON A-Foo(Bar));

Not 100% sure on the MySQL syntax but it should be something similar.
Posted by Per Christian Moen at Tue Jan 9 13:54:20 2007
Ehh managed to missed the point of MySQL foobar logic of the CREATE INDEX translation. That looks utter stupid. So just disregard my previous post. Now I appreciate Oracle even more:-)
Posted by Per Christian Moen at Tue Jan 9 13:57:32 2007

Name:


E-mail:


URL:


Comment:


Please enter "fudge" to prove you are a human