Resetting AUTO_INCREMENT on myISAM without rebuilding the table - mysql

Please help I am in major trouble with our production database. I had accidentally inserted a key with a very large value into an autoincrement column, and now I can't seem to change this value without a huge rebuild time.
ALTER TABLE tracks_copy AUTO_INCREMENT = 661482981
Is super-slow.
How can I fix this in production? I can't get this to work either (has no effect):
myisamchk tracks.MYI --set-auto-increment=661482982
Any ideas?
Basically, no matter what I do I get an overflow:
SHOW CREATE TABLE tracks
CREATE TABLE tracks (
...
) ENGINE=MYISAM AUTO_INCREMENT=2147483648 DEFAULT CHARSET=latin1

After struggling with this for hours, I was finally able to resolve it. The auto_increment info for myISAM is stored in TableName.MYI, see state->auto_increment in http://forge.mysql.com/wiki/MySQL_Internals_MyISAM. So fixing that file was the right way to go.
However, myisamchk definitely has an overflow bug somewhere in the update_auto_increment function or what it calls, so it does not work for large values -- or rather if the current value is already > 2^31, it will not update it (source file here -- http://www.google.com/codesearch/p?hl=en#kYwBl4fvuWY/pub/FreeBSD/distfiles/mysql-3.23.58.tar.gz%7C7yotzCtP7Ko/mysql-3.23.58/myisam/mi_check.c&q=mySQL%20%22AUTO_INCREMENT=%22%20lang:c)
After discovering this, I ended up just using "xxd" to dump the MYI file into a hexfile, edit around byte 60, and replace the auto_increment value manually in the hexfile. "xxd -r" then restores the binary file from the hex file. To discover exactly what to edit, I just used ALTER TABLE on much smaller tables and looked at the effects using diffs. No fun, but it worked in the end. There seems to be a checksum in the format, but it seems to be ignored.

Have you dropped the record with the very large key? I don't think you can change the auto_increment to a lower value if that record still exists.
From the docs on myisamchk:
Force AUTO_INCREMENT numbering for new records to start at the given value (or higher, if there are existing records with AUTO_INCREMENT values this large)

Related

Duplicate entry for key 'PRIMARY' - even though it is set to AUTO_INCREMENT

Bit of a strange one - I haven't changed the config, database, PHP code for this site for about 8 years. The whole time the guy I made it for has been adding, removing, changing stock with no issue, and suddenly today gets this error:
Duplicate entry '2541' for key 'PRIMARY'
executing (inserted generic values for the texts):
INSERT INTO stock (id,title,category,description,price,last_update,sold) VALUES(NULL,'Item name','72','Item description','0',1613723525,'no')
Searching around seemed to suggest this was a common problem when the primary key is not set to auto increment - makes sense. However, checking it out through phpMyAdmin, it definitely is.
Is there something in the index being set to primary rather than unique?
There are 5 other tables on the database but none are linked (as in hard links through the SQL, PHP handles all the cross-table stuff).
I checked and indeed there IS an item in the stock table with ID 2541 already. So why is that NULL AUTO_INCREMENT value converting to an existing id?
EDIT
I noticed that a table I created more recently (via MySQL Workbench probably) has a different setup for the indexes, with the addition of an id_UNIQUE index - do I need one of these on the stock table that is causing issues?
Based on your description and your comment "Interestingly, each time I refresh the ID it is attempted to insert (and failing on) increments by 1", I suspect that somehow the seed for the autoincrement for that table got changed to some value that was inserted at some time before.
How exactly that could happen I don't know.
Now, each time you attempt to insert a record this internal counter increments, so you see in the error message that the number increases (2541, 2542, ...) When you attempt to insert a row the internal counter increments regardless of whether the transaction is committed to the database or not. In your case the insert operation is rolled back, because the generated value violates the unique constraint and the internal counter keeps growing.
To change the seed you can run the following statement:
ALTER TABLE stock AUTO_INCREMENT=1234567;
You'll need to set it to the current MAX value that exists in the table, so that new entries that the system attempts to insert do not conflict.
See also How to set initial value and auto increment in MySQL?
This answer shows how to change the autoincrement seed in MySQL Workbench and in PhpMyAdmin. Maybe somebody did this accidentally and didn't notice.

Trying to convert MyISAM to InnoDB, result into error

I am trying to convert a very big table to InnDB. But it throws an error.
Here is the screenshot of the issue which came after running for 5 minutes.
UPDATE: This is a live production table where live data are coming. Seems like the auto_increment column is causing the issue. By the time the it applies the InnoDB engine new records are coming and the auto_increment is increased again.
Did you check official mysql documentation ? There is one useful text, maybe can help.
https://dev.mysql.com/doc/refman/8.0/en/converting-tables-to-innodb.html
Maybe just to try with ALTER TABLE your_table ENGINE=InnoDB;
I mean, without auto increment.

"Table already exists" when changing PK autoincrement in MySQL

I am quite new to MySQL and I have encountered a problem that I find quite puzzling. If I create a table with MySQL Workbench, when I set the PK I can choose it to auto-increment or not, as should be. However, if I change my mind later on, once the table has been created, I cannot alter the auto-increment flag any longer, as MySQL tells me that the "table already exists". That happens even if the table is empty.
The auto-generated SQL is as follows:
ALTER TABLE tablename
CHANGE COLUMN `ID` `ID` INT(11) NOT NULL AUTO_INCREMENT ;
and it fails with the error stated above. I have tried changing the algorithm and lock type, to no avail.
This does not happens in T-SQL or Oracle, for instance, so I fail to see a reason why it should fail in MySQL. Is there any way to fix this without having to drop and re-create the table?
Thanks.
From experience all the GUIs get a bit confused when you start changing primary keys, the number of error messages I've seen from SQL Server...
You don't need to drop the whole table, but it might be easiest to drop and then re-create the offending column.
Also, check out the MySQL dev docs, but I think either ALTER or MODIFY column are the two I'd go for and I'm not sure why the column name is there twice if you're not renaming it.
Ok, I discovered the culprit thanks to dbForge Studio. The same thing happens there, but this time the error is more explicit: I cannot change the auto-increment flag apparently because it is used as a foreign key on another table. I deleted the FK and then I was able to set the auto-increment.
Thank you all who helped me, I have learned some new things thanks to your comments.

When was my table last ALTERed?

I'm using mysql 5.1.41-3ubuntu12.10 and would like to know when my table was last ALTERed (or CREATEd, if it was never ALTERed).
SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA = SCHEMA();
gives the CREATE and last UPDATE time, but not AFAICT the last ALTER time.
The answer depends somewhat on the storage engine. The most reliable indicator of when the table was last altered is to look at the modified time on the .frm file in the data directory. That file should be updated every time you alter the table, even for changes like updating a column default that don't require a table rebuild.
information_schema.tables.create_time is a bit of a misnomer, since that value actually changes most of the time when you alter a table. However, this is one area where the storage engine is relevant. If you do an alter without a rebuild (like changing a column default value) in InnoDB then information_schema.tables.create_time is updated, but if you do the same in MyISAM information_schema.tables.create_time is not updated. In both cases the .frm file should be updated, so I'd recommend you check the file timestamp for the most accurate data if you have access to it.

Can I use zero in a column which has the AUTO_INCREMENT attribute

I'm using a MySQL 5.0 server. My requirement is to add one special row to an existing table which has an auto-increment primary key.
It would be very useful for future maintenance and management of the project if we were able to make the id of this row 0 (because it's easy to remember and easy to spot in manual observations).
Now, I know that MySQL has no problem with you using your own value for an autoincrement column, and my tests have shown that I can set the autoincrement primary key of a row to 0 with an UPDATE query. However, some concerns have been raised about how this might affect the auto-increment functionality of the column in future INSERTs.
My (limited) experiments have shown nothing strange and I can't find anything specific warning against this in the MySQL docs. That is, apart from this (emphasis mine): http://dev.mysql.com/doc/refman/5.0/en/create-table.html
There can be only one AUTO_INCREMENT column per table, it must be indexed, and it cannot have a DEFAULT value. An AUTO_INCREMENT column works properly only if it contains only positive values. Inserting a negative number is regarded as inserting a very large positive number. This is done to avoid precision problems when numbers “wrap” over from positive to negative and also to ensure that you do not accidentally get an AUTO_INCREMENT column that contains 0.
I am unable to find an explanation for what is wrong with having a value of zero in an AUTO_INCREMENT column, so can anyone tell me if having an AUTO_INCREMENT column that contains 0 is a bad thing?
As you have already discovered, it's not possible to asign a 0 to an auto increment field with an INSERT, you need to use an UPDATE. AFAIK there is nothing wrong with having a 0 in a row except when you try to dump and import. But that can be avoided by first inserting the data and then later marking it as an auto increment field.
Storing 0 is not a recommended practice. For example, if you dump the table with mysqldump and then reload it, MySQL normally generates new sequence numbers when it encounters the 0 values, resulting in a table with contents different from the one that was dumped. Enabling NO_AUTO_VALUE_ON_ZERO before reloading the dump file solves this problem. mysqldump now automatically includes in its output a statement that enables NO_AUTO_VALUE_ON_ZERO, to avoid this problem.