ALTER TABLE
Syntax
ALTER [ONLINE] [IGNORE] TABLE tbl_name [WAIT n | NOWAIT] alter_specification [, alter_specification] ... alter_specification: table_option ... | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name ] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD SPATIAL [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALTER [COLUMN] col_name SET DEFAULT literal | (expression) | ALTER [COLUMN] col_name DROP DEFAULT | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name] | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] | DROP [COLUMN] [IF EXISTS] col_name [RESTRICT|CASCADE] | DROP PRIMARY KEY | DROP {INDEX|KEY} index_name | DROP FOREIGN KEY fk_symbol | DROP CONSTRAINT constraint_name | DISABLE KEYS | ENABLE KEYS | RENAME [TO] new_tbl_name | ORDER BY col_name [, col_name] ... | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] | [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name | DISCARD TABLESPACE | IMPORT TABLESPACE | ALGORITHM [=] {DEFAULT|INPLACE|COPY} | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} | FORCE | partition_options | ADD PARTITION (partition_definition) | DROP PARTITION partition_names | COALESCE PARTITION number | REORGANIZE PARTITION [partition_names INTO (partition_definitions)] | ANALYZE PARTITION partition_names | CHECK PARTITION partition_names | OPTIMIZE PARTITION partition_names | REBUILD PARTITION partition_names | REPAIR PARTITION partition_names | EXCHANGE PARTITION partition_name WITH TABLE tbl_name | REMOVE PARTITIONING column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value | (expression)] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT}] [STORAGE {DISK|MEMORY|DEFAULT}] | data_type [GENERATED ALWAYS] AS ( <expression> ) {VIRTUAL | PERSISTENT} [UNIQUE] [UNIQUE KEY] [COMMENT 'string'] index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH | RTREE} index_option: KEY_BLOCK_SIZE [=] value | index_type | WITH PARSER parser_name | COMMENT 'string' | CLUSTERING={YES| NO} table_options: table_option [[,] table_option] ... (see CREATE TABLE options)
MariaDB starting with 10.0.2
IF EXISTS
and IF NOT EXISTS
clauses have been added for the following:
ADD COLUMN [IF NOT EXISTS] ADD INDEX [IF NOT EXISTS] ADD FOREIGN KEY [IF NOT EXISTS] ADD PARTITION [IF NOT EXISTS] CREATE INDEX [IF NOT EXISTS] DROP COLUMN [IF EXISTS] DROP INDEX [IF EXISTS] DROP FOREIGN KEY [IF EXISTS] DROP PARTITION [IF EXISTS] CHANGE COLUMN [IF EXISTS] MODIFY COLUMN [IF EXISTS] DROP INDEX [IF EXISTS]
Contents
- Syntax
- Description
- Index Type
- Character Sets and Collations
- WAIT/NOWAIT
- ADD COLUMN [IF NOT EXISTS] (col_name column_definition,...)
- DROP COLUMN [IF EXISTS] col_name [CASCADE|RESTRICT]
- MODIFY COLUMN
- CHANGE COLUMN
- ENABLE/ DISABLE KEYS
- ENGINE/FORCE For Re-building a Table
- IMPORT TABLESPACE
- ALGORITHM / When Does ALTER TABLE Copy All Data?
- LOCK
- Progress Reports
- Privileges
- Examples
- See Also
When IF EXISTS
and IF NOT EXISTS
are used in clauses, queries will not
report errors when the condition is triggered for that clause. A warning with
the same message text will be issued and the ALTER will move on to the next
clause in the statement (or end if finished).
This was done in MDEV-318.
MariaDB starting with 10.0.4
ALTER TABLE ... EXCHANGE PARTITION
was introduced in MariaDB 10.0.4
MariaDB starting with 10.2.1
DEFAULT
with expressions and DROP CONSTRAINT
was introduced in MariaDB 10.2.1
Description
ALTER TABLE
enables you to change the structure of an existing table.
For example, you can add or delete columns, create or destroy indexes,
change the type of existing columns, or rename columns or the table
itself. You can also change the comment for the table and the storage engine of the
table.
If another connection is using the table, a metadata lock is active, and this statement will wait until the lock is released. This is also true for non-transactional tables.
When adding a UNIQUE
index on a column (or a set of columns) which have duplicated values, an error will be produced and the statement will be stopped. To suppress the error and force the creation of UNIQUE
indexes, discarding duplicates, the IGNORE option can be specified. This can be useful if a column (or a set of columns) should be UNIQUE but it contains duplicate values; however, this technique provides no control on which rows are preserved and which are deleted. Also, note that IGNORE
is accepted but ignored in ALTER TABLE ... EXCHANGE PARTITION
statements.
For descriptions of the table options, see CREATE TABLE
.
This statement can also be used to rename a table. For details see RENAME TABLE
.
When an index is created, the storage engine may use a configurable buffer in the process. Incrementing the buffer speeds up the index creation. Aria and MyISAM allocate a buffer whose size is defined by aria_sort_buffer_size
or myisam_sort_buffer_size
, also used for REPAIR TABLE
. InnoDB/XtraDB allocates three buffers whose size is defined by innodb_sort_buffer_size
.
Index Type
See Storage Engine Index Types for details on permitted index_types for each storage engine.
CLUSTERING={YES|NO}
is only valid for Tokudb.
CREATE INDEX
and DROP INDEX
can also be used to add or remove an index.-
Character Sets and Collations
CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] [DEFAULT] CHARACTER SET [=] charset_name [DEFAULT] COLLATE [=] collation_name
See Setting Character Sets and Collations for details on setting the character sets and collations.
ADD COLUMN [IF NOT EXISTS] (col_name column_definition,...)
Adds a column to the table. The syntax is the same as in CREATE TABLE.
If you are using IF NOT_EXISTS
the column will not be added if it was not there already. This is very useful when doing scripts to modify tables.
The FIRST
and AFTER
clauses affect the physical order of columns in the datafile. Use FIRST
to add a column in the first (leftmost) position, or AFTER
followed by a column name to add the new column in any other position. Note that, nowadays, the physical position of a column is usually irrelevant.
DROP COLUMN [IF EXISTS] col_name [CASCADE|RESTRICT]
Drops the column from the table.
If you are using IF EXISTS
you will not get an error if the column didn't exist.
If the column is part of any index, the column will be dropped from them, except if you add a new column with identical name at the same time. The index will be dropped if all columns from the index were dropped.
If the column was used in a view or trigger, you will get an error next time the view or trigger is accessed.
MariaDB starting with 10.2.8
Dropping a column that is part of a multi-column UNIQUE
constraint is not permitted. For example:
CREATE TABLE a ( a int, b int, primary key (a,b) ); ALTER TABLE x DROP COLUMN a; [42000][1072] Key column 'A' doesn't exist in table
The reason is that dropping column a
would result in the new constraint that all values in column b
be unique. In order to drop the column, an explicit DROP PRIMARY KEY
and ADD PRIMARY KEY
would be required. Up until MariaDB 10.2.7, the column was dropped and the additional constraint applied, resulting in the following structure:
ALTER TABLE x DROP COLUMN a; Query OK, 0 rows affected (0.46 sec) DESC x; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | b | int(11) | NO | PRI | NULL | | +-------+---------+------+-----+---------+-------+
RESTRICT
and CASCADE
are allowed to make porting from other database systems easier. In MariaDB, they do nothing.
MODIFY COLUMN
Allows you to modify the type of a column. The column will be at the same place as the original column and all indexes on the column will be kept. Note that when modifying column, you should specify all attributes for the new column.
CREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY((a)); ALTER TABLE t1 MODIFY a BIGINT UNSIGNED AUTO_INCREMENT;
CHANGE COLUMN
Works like MODIFY COLUMN
except that you can also change the name of the column. The column will be at the same place as the original column and all index on the column will be kept.
CREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(a)); ALTER TABLE t1 CHANGE a b BIGINT UNSIGNED AUTO_INCREMENT;
ENABLE/ DISABLE KEYS
DISABLE KEYS
will disable all non unique keys for the table for storage engines that support this (at least MyISAM and Aria). This can be used to speed up inserts into empty tables.
ENABLE KEYS
will enable all disabled keys.
ENGINE/FORCE For Re-building a Table
ALTER TABLE
can force MariaDB to re-build the table. Before MariaDB 10.0, this was only done by setting the ENGINE
option to its old value. With MariaDB 10.0, the FORCE
option can be used. For example, for an InnoDB table, one can use:
ALTER TABLE tab_name ENGINE = InnoDB;
And, since MariaDB 10.0, this is equivalent to:
ALTER TABLE tab_name FORCE;
With InnoDB, ALTER TABLE will reclaim unused space (i.e. the space previously used for deleted rows) only if innodb_file_per_table is ON
. If the variable is OFF
, the space will not be reclaimed after an ALTER TABLE, but will be-re-used for new data that's later added.
IMPORT TABLESPACE
This is used to import an InnoDB table created with FLUSH TABLES FOR EXPORT.
The procedure to import is:
CREATE TABLE t…; /* using the output from SHOW CREATE TABLE */ ALTER TABLE t DISCARD TABLESPACE; /* effectively corrupts the database! */ /* copy the file t.ibd to the file system */ ALTER TABLE t IMPORT TABLESPACE;
Other storage engines doesn't require ALTER TABLE ... IMPORT
. The data is at once accessible after the data is copied.
ALGORITHM / When Does ALTER TABLE Copy All Data?
Before MariaDB 10.0, ALTER TABLE operations required making a temporary copy of the table, which can be slow for large tables. From MariaDB 10.0, many ALTER TABLE operations can be performed using in-place operations, without making a temporary copy of the table.
Over time, more operations have been made possible without a full copy. Here is a list of the actions that can be performed without having to copy the table:
- Changing a column name
- Changing display length of a integer like INT(2) -> INT(3)
- Changing a table comment
- Adding a new enum option last to a list
- Renaming a table
If multiple operations are needed, and they require the rebuilding of a table, it is convenient to group them in a single ALTER TABLE, so that only one rebuilding is done.
The ALGORITHM
clause, which has existed since MariaDB 10.0, can be used to exert some control over this behavior. There are three possible values:
- ALGORITHM=DEFAULT (the default behavior if no clause is specified)
- ALGORITHM=COPY
- ALGORITHM=INPLACE
With ALGORITHM=COPY
, the copy algorithm will be used even if it is not necessary. This can result in a lengthy table copy.
With ALGORITHM=INPLACE
, the in-place technique is used, which avoids possible lengthy table copies. If the operation would necessarily require a copy, an error is instead issued:
CREATE TABLE t1 (a INT, e ENUM ('red','green')); ALTER TABLE t1 MODIFY e EMUM('red','green','blue'), ALGORITHM=INPLACE; -> Query OK, 0 rows affected (0.11 sec) -> Records: 0 Duplicates: 0 Warnings: 0 ALTER TABLE t1 ADD c INT, ALGORITHM=INPLACE; -> ERROR 1845 (0A000): ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY.
The default behavior (ALGORITHM=DEFAULT
, or ALGORITHM
is not specified) usually only makes a copy when necessary. This can change if the value of the old_alter_table system variable is set to ON
(OFF
is default), in which case a copy of the table is made using a pre-MySQL 5.0 algorithm.
MariaDB starting with 10.0.11
Online ALTER TABLE has also worked for partitioned tables since MariaDB 10.0.11.
LOCK
Depending on the required operation and the used storage engine, different lock strategies can be used for ALTER TABLE
. In some cases no locks are required, other times only read locks are required, while sometimes write locks are required. The LOCK
clause can be used to require a certain lock strategy. It will be used if possible (even if you specify a strategy which is more restrictive than necessary), but if the required operation on the storage engine needs a more restrictive strategy, an error is issued. Allowed values for the LOCK
clause are:
DEFAULT
: The maximum allowed concurrency level is used.NONE
: No lock is acquired or an error is issued.SHARED
: A read lock is acquired or an error is issued.EXCLUSIVE
: A write lock is acquired.
A missing LOCK
clause is equivalent to LOCK=DEFAULT
.
Alternatively you can use ALTER ONLINE TABLE
to ensure that your ALTER TABLE
does not block concurrent operations (takes no locks). It is equivalent to LOCK=NONE
.
The INPLACE
algorithm sometimes requires temporary files. These files are created in the temporary directory, specified in the tmpdir server system variable.
Note that, if the COPY algorithm is used, the current values of innodb_file_per_table and innodb_file_format apply during the InnoDB tables re-creation.
Progress Reports
From MariaDB 5.3 you can get progress reports for ALTER TABLE
in clients
which support the new progress reporting protocol. From the mysql client:
ALTER TABLE test ENGINE=Aria; Stage: 1 of 2 'copy to tmp table' 46% of stage
The progress report is also shown in SHOW PROCESSLIST and the information_schema.processlist table.
Privileges
ALTER TABLE requires at least the ALTER privilege. Renaming a table requires the DROP, CREATE and INSERT privileges as well.
Examples
Adding a new column:
ALTER TABLE t1 ADD x INT;
Dropping a column:
ALTER TABLE t1 DROP x;
Modifying the type of a column:
ALTER TABLE t1 MODIFY x bigint unsigned;
Changing the name and type of a column:
ALTER TABLE t1 CHANGE a b bigint unsigned auto_increment;
Combining multiple clauses in a single ALTER TABLE statement, separated by commas:
ALTER TABLE t1 DROP x, ADD x2 INT, CHANGE y y2 INT;
Changing the storage engine:
ALTER TABLE t1 ENGINE = InnoDB;
Rebuilding the table (the previous example will also rebuild the table if it was already InnoDB):
ALTER TABLE t1 FORCE;