Mysql Auto Increment increasing by 2 and 1? - mysql

If I create a table with the following syntax,
CREATE TABLE IF NOT EXISTS `hashes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hash` binary(20) NOT NULL,
PRIMARY KEY (`id`,`hash`),
UNIQUE KEY (`hash`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE = 4 AUTO_INCREMENT=1
PARTITION BY KEY(`hash`)
PARTITIONS 10;
And insert queries with the following syntax
INSERT INTO hashes (hash) VALUES ($value) ON DUPLICATE KEY UPDATE hash = hash
Then the auto increment column works as expected both if the row is inserted or updated.
Although creating the table without the partition like below and inserting with the query above the auto increment value will increase by 1 on every update or insert causing the A_I column to be all over place as the query could do 10 updates and then 1 insert causing the column value to jump 10 places.
CREATE TABLE IF NOT EXISTS `hashes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hash` binary(20) NOT NULL,
PRIMARY KEY (`id`,`hash`),
UNIQUE KEY (`hash`)
) ENGINE=InnoDB AUTO_INCREMENT=1;
I understand why the value increases on an update with INNO_DB but I do not understand why it doesn't when the table is partitioned?

you cannot change that, but you can try something like this:
mysql> set #a:= (select max(id) + 2 from hashes);
mysql> insert into hashes (id) values ($value) on duplicate key update id=#a;
NOTE: the partitions change a little bit after mysql 5.6, which version do you have?

Related

Is lock needed for INSERT INTO ... SELECT value + 1 when value is UNIQUE?

Say I have this table:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`number` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Do I need some kind of lock if I insert data like this:
INSERT INTO test(number)
SELECT COALESCE(MAX(number), 0) + 1 FROM test;
In other words, if I have this statement executed in parallel multiple times, should I be worried that the same number could be inserted twice? I obviously will create a UNIQUE key (which will in fact be a composite key, that's why the classic AUTO INCREMENT feature does not fit my needs), but in that case should I be worry that a UNIQUE CONSTRAINT error might be thrown?
By default InnoDB uses auto-commit mode, so each query is a single transaction. So it will automatically perform the necessary locking to prevent duplication.

MySQL: Enforce an unique column without using an unique key

I have a column with data that exceeds MySQL's index length limit. Therefore, I can't use an unique key.
There's a solution here to the problem without using an unique key: MySQL: Insert record if not exists in table
However, in the comments, people are having issues with inserting the same value into multiple columns. In my case, a lot of my values are 0, so I'll get duplicate values very often.
I'm using Node and node-mysql to access the database. I'm thinking I can have a variable that keeps track of all values that are currently being inserted. Before inserting, I check if the value is currently being inserting. If so, I'll wait until it finishes inserting, then continue execution as if the value was originally inserted. However, I feel like this will be very error prone.
Here's part of my table schema:
CREATE TABLE `links` (
`id` int(10) UNSIGNED NOT NULL,
`url` varchar(2083) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
`likes` int(10) UNSIGNED NOT NULL,
`tweets` int(10) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `links`
ADD PRIMARY KEY (`id`),
ADD KEY `url` (`url`(50));
I cannot put an unique key on url because it can be 2083 bytes, which is over MySQL's key size limit. likes and tweets will often be 0, so the linked solution will not work.
Is there another possible solution?
If you phrase your INSERT in a certain way, you can make use of WHERE NOT EXISTS to check first if the URL does not exist before completing the insert:
INSERT INTO links (`url`, `likes`, `tweets`)
SELECT 'http://www.google.com', 10, 15 FROM DUAL
WHERE NOT EXISTS
(SELECT 1 FROM links WHERE url='http://www.google.com');
This assumes that the id column is a primary key/auto increment, and MySQL will automatically assign a value to it.

MySQL sorts tables with one unique column automatically. Where is this documented?

I'm running MySQL 5.5 and found behaviour I didn't know of before.
Given this create:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UQ` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
With these inserts:
insert into test (name) values ('b');
insert into test (name) values ('a');
And this select:
select * from test;
MySQL does something I wasn't aware of:
2 a
1 b
It sorts automatically.
Given a table with one extra, non-unique column:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL,
`other_column` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UQ` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And the same inserts (see above), the select (see above) gives this result:
1 b NULL
2 a NULL
Which is kind of expected.
Where is the behaviour of the first query (SQL Fiddle) documented? I'd like to see more of these peculiar things.
MySQL does not sort result sets automatically. The ordering of a result set is indeterminate unless the query specifies an order by clause.
You should never rely on any sort of "implicit" ordering. Just because you see it in 1 (or 100 queries). In fact, without an order by, the same query can return results in different orders on subsequent runs (although I'll admit that this regularly occurs in other database, it is unlikely in MySQL).
Instead, add the ORDER BY. Ordering by a primary key is remarkably efficient, so you don't have to worry about performance.

How to select a random row from a table in MySQL?

Let's say I have a table with an integer column called ID being a primary key. It is unique and not-null, but we cannot guarantee it being sequential without gaps. I.e. we may have rows with ID = 1,2,6,7,8 and we do not have rows with ID 3,4,5 etc etc.
This is why we cannot just generate a random number and get a row with that corresponding ID.
Also we want all rows to have equal chance of being selected, so b/c of the gaps in ID values we cannot use simple approach with random number in 0 to max(id) range
The number of rows in the table is not known either.
How can I select a random row from that table?
Here is the table schema:
CREATE TABLE IF NOT EXISTS `test_data` (
`id` int(10) unsigned NOT NULL,
`create_date` datetime DEFAULT NULL,
`text_1` varchar(255) NOT NULL DEFAULT 'BMqFXUslYnGsYsPxHTtZVbcwnEWFmSXxTAUV9YxXXDH5ClUEUO8kFz0cW1xC3o9aMSwabnEr43W23KZnKvrk8PHEJv18SU5JHTH72sLTtleitBJBIWmIpul7LtuYOpc4iRDqEAT80UeG7L2l4r1pr2jEMW7222reAOuIcBIUcsH9LYlojeQjVkc9ZhYXgnN3xRGHLJ3L0MGoXO4GHttEv053DqkkKYEye34bpGI2tJ0IE9M8BIFf2u08jB50nhD',
`text_2` varchar(255) NOT NULL DEFAULT 'hoA6tWi8AEcikkJM50Mz800PGTUKNnyj3OCKhyJ4ExaJf6bYbqXlNWo4y0XXXo7HuvsNgYWnn16211RbKDesQ852QA33s1eni4pBoraEs3YiV0W69yMY7Nf0pvQI198HUVKYPWk9zpK38PDphtPJXO2z5Wb8mbBN0gN8iK5xzUQQDwoAJlO3Z8xXn2OWyVjKswRbZNKW6l0tvn0zN4S4BoR9gkN7s4Ov9tTGeF4uwWYhPEs0WsDqatMjmbnMQmC'
) ENGINE=InnoDB;
ALTER TABLE `test_data`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `id` (`id`);
Have you tried RAND()?
SELECT * FROM `test_data` ORDER BY RAND() LIMIT 1;

MySQL stop inserting when duplicate key condition is met

I have a table constructed by the followinng:
CREATE TABLE IF NOT EXISTS test_table (
ID int(11) NOT NULL AUTO_INCREMENT,
ProfileID int(11) NOT NULL,
ForeignID int(11) NOT NULL,
PRIMARY KEY (ProfileID,ForeignID) )
ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
I want to do something a little peculiar though, say there are 4 records in the database:
RecA, RecB, RecC, RecD
I would like to run the following query and have the insert behavior stop when a duplicate key was encountered:
INSERT IGNORE INTO test_table (ProfileID, ForeignID) VALUES(RecE, RecF, RecA, RecB, RecG);
So the query would only insert RecE and RecF, is there a way to do this in MySQL, perhaps using ON DUPLICATE KEY? Ideally the execution would just be terminated once a duplicate has been found, I am not too familiar with SQL syntax though.
Where RecG was explicitly not inserted.