When I alter MySQL table, add new column for my log table. specific statement like below:
alter table log_xxx add column `new_column` smallint NOT NULL after post_date;
Will above statement will lock table log_xxx if I execute SQL to insert some records when I execute this alter statement?
I make some test, execute insert statement do not include new column successfully while the alter statement still under processing. So I have no idea about the alter table add column will lock table or not?
Is there anyone who knows about this problem?
It depends on the storage engine, if you use InnoDB, it may alter table in place and not block the DML operation, and if then MyISAM is used, the update and write operations that start after alter begins, will be blocked until the new table is ready.
Those links maybe help:
https://dev.mysql.com/doc/refman/5.7/en/alter-table.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-create-index-overview.html
Related
I'm digging on MySQL's online ddl (5.7)
For some operations, it support ALGORITHM such as INPLACE, COPY.
This is I understood
INPLACE modifies original table
COPY creates temporary table -> copies all records to it -> and replace original table
Plus, this link refers that adding index to a table does not rebuild table
https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html
but, after I add index and check tables CREATE_TIME it is updated
CREATE DATABASE db;
USE db;
CREATE TABLE hello(id int primary key auto_increment, col varchar(20));
SELECT CREATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='db' and TABLE_NAME='hello';
ALTER TABLE hello ADD INDEX `idx_col` (col), ALGORITHM=INPLACE;
# CREATE TIME is updated
SELECT CREATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='db' and TABLE_NAME='hello';
I'm not sure whether CREATE_TIME doesn't actually mean table creation time, or
whether table is rebuilt even with ALGORITHM=INPLACE specified.
Could anyone help me find out what is going on here?
I have the following sql code to create a table
CREATE TABLE db.object (
`objid` bigint(20) NOT NULL AUTO_INCREMENT,
`object_type` varchar(32) NOT NULL,
PRIMARY KEY (`objid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
However, the values in the objid are coming out as 1,2,3... (The insert statement is not adding the ids)
Shouldn't AUTO_INCREMENT=2 make the objid start from 2 instead of 1
With InnoDB tables, the AUTO_INCREMENT value will be reset to the maximum value (plus 1) when the table is opened. The auto increment value exists only in memory, it is not persisted on disk.
A table open would happen, for example, when the MySQL instance was shutdown and then restarted, and a reference is made to the table.
A table can also be closed at other times. For example, when open_table_cache is exceeded (that is, when a large number of other tables is opened), MySQL will close some of the open tables, to make room in the cache for newly opened tables.
I believe this behavior is documented somewhere in the MySQL Reference Manual.
I used your SQL, created the object table and entered two values for object_type and objid started at 2. Can't see anything wrong here...
It might. There are enough exceptions and gotchas with auto-inc on InnoDB tables that it bears urging a full review of the documentation.
That said, there is one scenario I can think of where MySQL ignores the initializer value. I'll quote the documentation:
InnoDB uses the in-memory auto-increment counter as long as the server runs. When the server is stopped and restarted, InnoDB reinitializes the counter for each table for the first INSERT to the table, as described [here]:
InnoDB executes the equivalent of the following statement on the first insert into a table containing an AUTO_INCREMENT column after a restart:
SELECT MAX(ai_col) FROM table_name FOR UPDATE;
A server restart also cancels the effect of the AUTO_INCREMENT = N table option in CREATE TABLE and ALTER TABLE statements, which you can use with InnoDB tables to set the initial counter value or alter the current counter value.
So if you create that table, then do a server restart (like as part of a deployment process), you'll get a nice value of 1 for the initial row. If you want to countermand this, you need to create the table, then insert a dummy row with the auto-inc value you want, then restart, then delete the dummy row.
I'm converting an existing database from MyISAM to InnoDB and implementing various foreign keys, I'm having an issue with running the convert script on my database though:-
I'm running all queries as below
DELETE FROM example WHERE user NOT IN (select id FROM users);
ALTER TABLE `example` CHANGE `user` `user` INT( 11 ) UNSIGNED NOT NULL ;
ALTER TABLE example ADD FOREIGN KEY (user) REFERENCES users(ID);
ALTER TABLE example ADD FOREIGN KEY (car) REFERENCES cars(ID);
When I run all queries it fails due to a foreign key constraint, due to the fact the DELETE statement hasn't run - if I run them individually, it's fine - is it an issue with commit on the innodb database or is it due to speed of the delete not completing before the next query?
Is it also ok to have two foreignkeys of ID? (two different tables users.id and cars.id).
Thanks!
No idea of what the error message might say or what you're trying to accomplish but ALTER TABLE is a DDL statement and those cannot be rollbacked in MySQL. The Statements That Cause an Implicit Commi manual chapter explains:
The statements listed in this section (and any synonyms for them)
implicitly end any transaction active in the current session, as if you had done a COMMIT before executing the statement. As of MySQL
5.5.3, most of these statements also cause an implicit commit after executing;
[...]
Data definition language (DDL) statements that define or modify database objects
[...]
ALTER TABLE, CREATE TABLE, and DROP TABLE do not commit a transaction
if the TEMPORARY keyword is used. (This does not apply to other
operations on temporary tables such as CREATE INDEX, which do cause a
commit.) However, although no implicit commit occurs, neither can the
statement be rolled back. Therefore, use of such statements will
violate transaction atomicity: For example, if you use CREATE
TEMPORARY TABLE and then roll back the transaction, the table remains
in existence.
I have a table
CREATE TABLE `uli` (
`id` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
The table shall always contain one value in one row. But it could be changed often. I would like to make a select, lock the table for other connections, update a value and the unlock.
For example, the following code works excellent:
LOCK TABLES uli WRITE;
SELECT * FROM uli;
UPDATE uli SET id=id+1;
UNLOCK TABLES;
While first connection do not unlock, all other connection will wait, and only after unlock could see new value. That is exactly what I want. Is it exists some more elegant solution? Does it matter MyIsam or Innodb table to use?
You are locking for write, which means selects will still see the old value before the update. Also you are not doing anything with your select. If you use InnoDB and SERIALIZABLE isolation level, all you need is the update statement.
I'm trying to remove duplicates from a MySQL table using ALTER IGNORE TABLE + an UNIQUE KEY. The MySQL documentation says:
IGNORE is a MySQL extension to standard SQL. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, only the first row is used of rows with duplicates on a unique key. The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.
When I run the query ...
ALTER IGNORE TABLE table ADD UNIQUE INDEX dupidx (field)
... I still get the error #1062 - Duplicate entry 'blabla' for key 'dupidx'.
The IGNORE keyword extension to MySQL seems to have a bug in the InnoDB version on some version of MySQL.
You could always, convert to MyISAM, IGNORE-ADD the index and then convert back to InnoDB
ALTER TABLE table ENGINE MyISAM;
ALTER IGNORE TABLE table ADD UNIQUE INDEX dupidx (field);
ALTER TABLE table ENGINE InnoDB;
Note, if you have Foreign Key constraints this will not work, you will have to remove those first, and add them back later.
Or try set session old_alter_table=1 (Don't forget to set it back!)
See: http://mysqlolyk.wordpress.com/2012/02/18/alter-ignore-table-add-index-always-give-errors/
The problem is that you have duplicate data in the field you're trying to index. You'll need to remove the offending duplicates before you can add a unique index.
One way is to do the following:
CREATE TABLE tmp_table LIKE table;
ALTER IGNORE TABLE tmp_table ADD UNIQUE INDEX dupidx (field);
INSERT IGNORE INTO tmp_table SELECT * FROM table;
DROP TABLE table;
RENAME TABLE tmp_table TO table;
this allows you to insert only the unique data into the table