Yesterday I found one problem on my project. For some reason for usual insert mysql did increase auto increment from 8 symbols to 10. In binlogs I found this
SET INSERT_ID=2147483646/*!*/;
# at 2638426
#140514 18:49:36 server id 31245 end_log_pos 2638810 Query thread_id=178500933 exec_time=0 error_code=0
SET TIMESTAMP=1400093376/*!*/;
INSERT INTO deals SET NAME = '###', PRICE = 125
But it must be around 26513863
ID field is: `ID` int(10) NOT NULL AUTO_INCREMENT
Table type: InnoDB
Mysql version: 5.5.31
Maybe someone know how can it be, or have any ideas?
A failed insert can still cause the auto-increment column to increase. If your program went into an infinite loop of failures it could cause the limit to be reached.
It's also possible to set the auto-increment programmatically to a specific value.
ALTER TABLE yourtable AUTO_INCREMENT = 12345;
from "Mark Byers" in this question stackoverflow
Related
So I'm working on a project that have the following schema on a MySQL 5.7 database:
CREATE TABLE `voucher` (
`id` varchar(36) NOT NULL,
`voucher_status_id` int(11) NOT NULL,
`situation_code` varchar(30) DEFAULT NULL,
`organization_id` int(11) DEFAULT NULL,
`code` varchar(15) NOT NULL,
`authorization_code` varchar(7) NOT NULL
.. other columns omitted for brevity
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
This table have ~ 2M rows and stores a pool of Vouchers.
The system get vouchers with voucher_status_id = 1 to sell.
The sale process is basically:
The user inputs the quantity X of Vouchers he wants to buy.
The application query the database with this select: SELECT v.* FROM voucher v where v.voucher_status_id = ? and v.organization_id = ? limit X for update
Then do the rest (update the voucher status, etc), and commit the transaction.
Things to notice: there's no SKIP LOCKED feature available, because this application is using MySQL 5.7; this pool of vouchers exist because the process of generating a voucher code is complex and made by a scheduled process on another system that load this table; the id column is a UUID v4
As you noticed, the select statement from above does lock some rows and it causes a lot of problems to the other sales concurrently happening and often (really) inccurs in Lock wait timeout exceeded errors.
By reading MySQL documentation, I found that it locks all the rows it has to scan while doing select ... for update statements.
A SELECT ... FOR UPDATE reads the latest available data, setting
exclusive locks on each row it reads. Thus, it sets the same locks a
searched SQL UPDATE would set on the rows.
The application is getting tons of Lock wait timeout exceeded errors. How can this be avoided in this case?
Another dev proposed randomly select rows by using ORDER BY RAND(), but it would end up with the same problem as a test I made clearly showed us:
Transaction A:
begin;
select * from voucher v where v.voucher_status_id = 1
and organization_id = 5
order by rand()
limit 5
for update;
Transaction B:
begin;
select * from voucher v where v.voucher_status_id = 1
and organization_id = 5
order by rand()
limit 10
for update;
Transaction B gets locked until Transaction A is commited.
How would you solve such situation?
In a table in mysql db (version: 5.7.37) I have an auto-increment field (id column).
The table is a huge one, but sometime we delete records (so id of 1 million is not 1 millions records) - still a huge one after the deletion.
Sometime the id reaches the maximum integer value (2147483647).
I won't change to bigint (it is complicated - there is limitation in code also).
I want to do it cyclic - when it reaches 2147483647, the next value will be 1, so I want to do:
alter table mytable AUTO_INCREMENT=1;
That may seems work with no any exception (for a fraction of second), but when I do:
SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES t
WHERE TABLE_SCHEMA = 'myschema'
AND TABLE_NAME = 'mytable';
I see that the AUTO_INCREMENT for above is still of value: 2147483647 and not of value 1.
If I do something like:
SET FOREIGN_KEY_CHECKS = 0;
set unique_checks=0;
alter table mytable
change column `id` `id` int(11) NOT NULL;
set unique_checks=1;
SET FOREIGN_KEY_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 0;
set unique_checks=0;
alter table mytable
change column `id` `id` int(11) NOT NULL AUTO_INCREMENT;
SET FOREIGN_KEY_CHECKS = 1;
SET unique_checks=1;
alter table paranoid_zero AUTO_INCREMENT=1;
The above take too long time (few minutes), and still AUTO_INCREMENT value checked by query:
SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES t
WHERE TABLE_SCHEMA = 'myschema'
AND TABLE_NAME = 'mytable';
is equal to 2147483647.
How can I update auto increment value (fast) in a proper way with mysql query.
Thanks.
An AUTO_INCREMENT will not go below MAX(id). That is, if there are rows still in the table, you cannot change the value all the way down to 1. That is, if your DELETEs did not remove the row with ids near 2147483647, you would gain much breathing room.
You seem to have ``INT SIGNED. Changing to INT UNSIGNEDwould give you about 4 billion limit. But it will be just as slow as changing toBIGINT`.
Use IODKU instead of REPLACE. All flavors of INSERT will assign an id before realizing that it is not needed. Could this be 'burning' ids faster than you realize?
Faster DELETEs: http://mysql.rjweb.org/doc.php/deletebig
Batch Normalization
(And I may have other tips relating to your problem and its cause.
SCENARIO
ALTER TABLE {TABLE NAME} AUTO_INCREMENT = 1;
INSERT INTO {TABLE NAME} ({COLUMN}) VALUES (1);
(this is only record in table after auto increment was updated)
SELECT AUTO_INCREMENT FROM information_schema.TABLES
WHERE TABLE_SCHEMA = {DATABASE NAME}
AND TABLE_NAME = {TABLE NAME};
the last select auto_increment is returning the old value before execution alter table in step 1) and I don't understand why and hot to fix it or maybe alter table in step 1) is not correct way to reset auto_increment.
THX
PS. I know a bit but not everything. I was researching this problem and didn't find satisfactory/explanatory answer.
The INFORMATION_SCHEMA doesn't update to reflect recent alterations. MySQL 8.0 changed it so it only updates once every 24 hours.
You can set this:
SET GLOBAL information_schema_stats_expiry=0;
That will make INFORMATION_SCHEMA update immediately, at the cost of some overhead on your system.
I had the issue where the information schema wasn't being immediately updated.
To fix this I ran:
SET PERSIST information_schema_stats_expiry = 0;
As using SET GLOBAL didn't work for me.
Hope this helps somebody else.
I guess you must set AUTO_INCREMENT = 1 not 0
I'm seeing a weird behavior when I INSERT some data into a table and then run a SELECT query on the same table. This table has an auto-increment primary key (uid), and this problem occurs when I try to then select results where 'uid IS NULL'.
I've golfed this down to the following SQL commands:
DROP TABLE IF EXISTS test_users;
CREATE TABLE test_users (uid INTEGER PRIMARY KEY AUTO_INCREMENT, name varchar(20) NOT NULL);
INSERT INTO test_users(name) values('foo');
SELECT uid FROM test_users WHERE uid IS NULL;
SELECT uid FROM test_users WHERE uid IS NULL; -- no output from this query
I'd expect SELECT uid FROM test_users WHERE uid IS NULL to never return anything, but it does, sometimes. Here's what I've found:
Version of MySQL/MariaDB seems to matter. The machine having this problem is running MySQL 5.1.73 (CentOS 6.5, both 32-bit and 64-bit). My other machine running 5.5.37-MariaDB (Fedora 19, 64-bit). Both running default configs, aside from being configured to use MyISAM tables.
Only the first SELECT query after the INSERT is affected.
If I specify a value for uid rather than let it auto-increment, then it's fine.
If I disconnect and reconnect between the INSERT and SELECT, then I get the expected no results. This is easiest to see in something like Perl where I manage the connection object. I have a test script demonstrating this at https://gist.github.com/avuserow/1c20cc03c007eda43c82
This behavior is by design.
It's evidently equivalent to SELECT * FROM t1 WHERE id = LAST_INSERT_ID(); which would also work only from the connection where you just did the insert, exactly as you described.
It's apparently a workaround that you can use in some environments that make it difficult to fetch the last inserted (by your connection) row's auto-increment value in a more conventional way.
To be precise, it's actually the auto_increment value assigned to the first row inserted by your connection's last insert statement. That's the same thing when you only inserted one row, but it's not the same thing when you insert multiple rows with a single insert statement.
http://dev.mysql.com/doc/connector-odbc/en/connector-odbc-usagenotes-functionality-last-insert-id.html
CREATE TABLE dummy (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
name VARCHAR( 30 ) NOT NULL
) ENGINE = MYISAM ;
and running this query:
SELECT GROUP_CONCAT(`name` SEPARATOR "||") FROM `dummy`
This query joins name column in all rows with || in a single column. BUT, the result is truncated with mysql configuration as explained in mysql manual :
"... result is truncated to the maximum length that is given by the group_concat_max_len system variable, which has a default value of 1024 ..."
Also in manual it is said that this setting can be changed in run time by the following syntax:
SET [GLOBAL | SESSION] group_concat_max_len = val;
Does changing this configuration works in all mysql server environments? If not, how can I achieve the same result without GROUP_CONCAT without limits?
Also, I think that changing the configuration will not solve my problem because I don't know what to set the value of group_concat_max_len because number of rows in dummy table can be any number.
Thanks.
Have you tried using stored procedure to accomplish your task? You can create a temporary table with a single row/column and append to it while fetching rows from your table. In the end just SELECT the single value from the temporary table.
You can find information about stored routines in mysql manual and other places.