Mysql Alter table timing depending on presence of foreign keys - mysql

We have a situation where we have a table A and B, where A has few thousand rows ( approx 50k) and B has few million rows (approx 5M). Table B has a column which points to Table A's primary key. We need to add a column to table A and are concerned that while alter statement runs, it would perhaps have a read lock on table B.
My first question is, is that true, that table B would get locked while altering table A? And if yes, would it be better to drop the foreign key from B to A first then run the alter statements, and recreate the foreign key afterwards.
We are using MySQL 5.5, InnoDB and separate files for each table.

Did you try this?
set foreign_key_checks = 0;
ALTER TABLE ...;
set foreign_key_checks = 1;
You can remove the foreign key, if it is safe to remove permanently. But removing the foreign key constraint temporarily and then add it again after the ALTER statement would be an overhead.

Related

AUTO_INCREMENT not working as expected [duplicate]

I've been using InnoDB for a project, and relying on auto_increment. This is not a problem for most of the tables, but for tables with deletion, this might be an issue:
AUTO_INCREMENT Handling in InnoDB
particularly this part:
AUTO_INCREMENT column named ai_col: After a server startup, for the first insert into a table t, InnoDB executes the equivalent of this statement:
SELECT MAX(ai_col) FROM t FOR UPDATE;
InnoDB increments by one the value retrieved by the statement and assigns it to the column and to the auto-increment counter for the table.
This is a problem because while it ensures that within the table, the key is unique, there are foreign keys to this table where those keys are no longer unique.
The mysql server does/should not restart often, but this is breaking. Are there any easy ways around this?
If you have a foreign key constraint, how can you delete a row from table A when table B references that row? That seems like an error to me.
Regardless, you can avoid the reuse of auto-increment values by resetting the offset when your application starts back up. Query for the maximum in all the tables that reference table A, then alter the table above that maximum, e.g. if the max is 989, use this:
alter table TableA auto_increment=999;
Also beware that different MySQL engines have different auto-increment behavior. This trick works for InnoDB.
So you have two tables:
TableA
A_ID [PK]
and
TableB
B_ID [PK]
A_ID [FK, TableA.A_ID]
And in TableB, the value of A_ID is not unique? Or is there a value in TableB.A_ID that is not in TableA.A_ID?
If you need the value of TableB.A_ID to be unique, then you need to add a UNIQUE constraint to that column.
Or am I still missing something?
Use a foreign key constraint with 'SET NULL' for updates and deletes.
Create another table with a column that remembers the last created Id. This way you don't have to take care of the max values in new tables that have this as foreign key.
I checked.
alter table TableA auto_increment=1;
does NOT work.
And the reason I found in two documents
http://docs.oracle.com/cd/E17952_01/refman-5.1-en/innodb-auto-increment-handling.html
InnoDB uses the following algorithm to initialize the auto-increment counter for a table t that contains an AUTO_INCREMENT column named ai_col: After a server startup, for the first insert into a table t, InnoDB executes the equivalent of this statement:
SELECT MAX(ai_col) FROM t FOR UPDATE;
InnoDB increments the value retrieved by the statement and assigns it to the column and to the auto-increment counter for the table. By default, the value is incremented by one. This default can be overridden by the auto_increment_increment configuration setting.
and
http://docs.oracle.com/cd/E17952_01/refman-5.1-en/alter-table.html
You cannot reset the counter to a value less than or equal to any that have already been used.
This is the reason why alter table will not work. I think that only option is to wipe out data and rewrite it in a new table with new id.
In my case table was logfile , so I just did:
RENAME TABLE SystemEvents To SystemEvents_old;
CREATE TABLE SystemEvents LIKE SystemEvents_old;

what will happen to orphaned rows in a table if I add foreign key to one of the columns

A table in an RDBMS that has a foreign key column but was not marked as one has lead to many orphaned rows.
What will change if I Alter the table and make that column a foreign key constraint.
Table:
Posts: id, title, body, user_id (currently not marked as FK)
Will I lose the orphaned rows?
EDIT:
1. Would it make sense to recreate the table with the correct FK constraints and port data from the old table to the new one?
MySQL will disallow creation of the foreign key index if it would result in "orphaned" records in the child table.
You can force creation of the index with
set foreign_key_checks = 0;
before running your alter query - but you will eventually have to clean up the dangling records.

how to truncate the primary key table if we have foreign key constraint for a column in another table?

Hi i am using sql server 2008 r2,
i have a genuine problem.
i have a Table A and Table B,
where i have a column IID in table A as a primary key constraint.
and the same column i.e. IID in table B as a foreign key constraint.
i have a situation where i wanted to truncate the table A. while running query Truncate table A it give me following error.
Msg 4712, Level 16, State 1, Line 1
Cannot truncate table 'A' because it is being referenced by
a FOREIGN KEY constraint.
my problem i cant do any DML & DDL operation on table B.
how can i truncate table A ?
Thanks! in advanced.
The only way to allow a truncate is to drop the foreign key constraint(s) against table A. It doesn't matter if the constraint is disabled or if both tables are empty, SQL Server still will not allow it. So if you have the definition of the foreign key handy, you could do:
ALTER TABLE dbo.TableB DROP CONSTRAINT FK_whatever;
TRUNCATE TABLE dbo.TableA;
ALTER TABLE dbo.TableB ADD CONSTRAINT FK_Whatever
FOREIGN KEY ...;
Otherwise as #Damien says the solution to your "genuine problem" is to use DELETE instead of TRUNCATE. If you also were using TRUNCATE to reset the IDENTITY column, you can perform a DELETE and then a DBCC CHECKIDENT('dbo.TableA', RESEED, 1);...
If you can't do anything against Table B, then you're going to have to let SQL Server validate that its not removing rows which are referenced by Table B.
So, it's nice, slow, logged DELETE FROM A.

MySQL: ALTER IGNORE TABLE gives "Integrity constraint violation"

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

Can I convert Innodb with foreign directly into mysiam?

I want to convert the db with innodb tables into myisam, all of them. How can I do these? there are some foreign keys exist among tables.
how can I make this in the best way?
You can't convert directly from InnoDB to MyISAM while the foreign keys are still there. You have to remove the constraints first. To do this, for each table follow these steps:
Issue SHOW CREATE TABLE tablename
For each CONSTRAINT ... FOREIGN KEY declaration in the output, you will need to issue ALTER TABLE tablename DROP FOREIGN KEY x where x is the identifier that appears between CONSTRAINT and FOREIGN KEY.
Issue SHOW CREATE TABLE tablename again. The foreign key constraints may have left behind indexes (since InnoDB requires an index on each foreign key, and it won't necessarily remove them just because you have removed the constraint). For each index you decide you no longer want, issue ALTER TABLE tablename DROP INDEX indexname.
Once you have done this for all tables that are involved with constraints, you can convert tables to MyISAM individually using ALTER TABLE tablename ENGINE=MYISAM.