I like to set internal AUTO_INCREMENT counter for the table, which uses MyISAM and composite primary key - but just for specific PK combination.
If I use
ALTER TABLE tablename AUTO_INCREMENT = 1;
It will set internal counter for all composite PK combinations, which I don't want.
I need something like
ALTER TABLE tablename AUTO_INCREMENT = 1 WHERE prefix = 5 AND suffix = X;
It does not work this way. Is there any possibility to change only counter for specific PK combination in MyISAM table?
Table:
CREATE TABLE `ENG__faktury_counter`
(
`year` int(10) NOT NULL,
`prefix` varchar(10) NOT NULL,
`DIC` varchar(50) NOT NULL,
`id_counter` int(15) NOT NULL AUTO_INCREMENT ,
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`year`,`prefix`,`DIC`,`id_counter`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
There is virtually zero use for ALTER TABLE ... AUTO_INCREMENT=....
If you are using MyISAM and have
foo ...
id ... AUTO_INCREMENT
PRIMARY KEY(foo, id) -- where the _2nd_ column is auto-inc
Then there is nothing to do to get
foo id
--- --
cat 1
cat 2
dog 1
bird 1
cat 3
bird 2
bird 3
dog 2
regardless of the order in which you insert the rows.
If this does not address your question, please enhance it with an example and SHOW CREATE TABLE.
Related
I want to create a table name Users where I should have have columns User, cookieID, sessionID, Geo and then I want to first three columns to have some random unique value assigned automatically. I tried to make all three columns AUTO_INCREMENT with User column PRIMARY and 'cookieIDandsessionIDcolumnUNIQUE`. The SQL code is:
CREATE TABLE `users` ( `User` VARCHAR(20) NOT NULL AUTO_INCREMENT ,
`cookieID` INT(20) NULL DEFAULT NULL AUTO_INCREMENT ,
`sessionID` INT(20) NULL DEFAULT NULL AUTO_INCREMENT ,
`Geo` VARCHAR(30) NULL DEFAULT NULL ,
PRIMARY KEY (`User`), UNIQUE (`cookieID`), UNIQUE (`sessionID`), UNIQUE (`Geo`));
But, it did not work because only one column can be declared as AUTO_INCREMENT which must be PRIMARY.
What is the another approach to do this?
Since the auto-increment cannot be applied to multiple to rows and there no option for sequence in MySQL. You can use triggers for the unique update of the row with datetime.
Change to table creation to be of single auto-increment row.
CREATE TABLE `users` ( `User` VARCHAR(20) NOT NULL,
`cookieID` INT(20) NULL DEFAULT NULL,
`sessionID` INT(20) NULL DEFAULT NULL AUTO_INCREMENT ,
`Geo` VARCHAR(30) NULL DEFAULT NULL,
PRIMARY KEY (`User`), UNIQUE (`cookieID`), UNIQUE (`sessionID`), UNIQUE (`Geo`));
Create a trigger on the same table as below. You can set the unique values under the SET for as many column as you want.
CREATE DEFINER=`root`#`localhost` TRIGGER `users_BEFORE_INSERT` BEFORE INSERT ON `users` FOR EACH ROW BEGIN
SET
NEW.cookieID = (SELECT curdate()+curtime());
END
Now when you insert into the table as below.
insert into `users`(`User`) values("test");
You table looks like this.
User cookieID sessionID Geo
test 20315169 0 NULL
If the value which are auto incrementing, you wanna keep both values the same. Then copy the value of one column to another during insertion time of new value.
We have an table bellow:
CREATE TABLE usable (
id bigint(20) NOT NULL AUTO_INCREMENT primary key ,
device VARCHAR(64) NOT NULL,
key1 VARCHAR(128) NOT NULL,
key2 VARCHAR(128) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
create unique index uidx_usable on usable (key1);
CREATE TABLE used
(
usedid bigint(20) PRIMARY KEY NOT NULL AUTO_INCREMENT primary key,
devid VARCHAR(64) NOT NULL,
key1 VARCHAR(128) NOT NULL ,
key2 VARCHAR(64) NOT NULL '
created_time timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
create unique index uidx_used on used (key1);
create unique index uidx_used_deviceid on used (devid);
select 1 record from usable table wih muti-thread.
insert into record to used table.
delete this record from usable table.
my work goes here:
START TRANSACTION
SELECT * FROM usable WHERE device = 555 order by rand() limit 1 FOR UPDATE;
insert into used (key1, key2) values (key1, key2 from step 1 select result);
delete from usable where id = (id from step 1 select result);
COMMIT
The tables are in InnoDB engine. AutoCommit is set to ON in the global variables.
There is no problem for just one thread, about 100ms with these three sql cmds. Is there solution to improve it?
but, thread begin to hang up when 100 QPS.
How to congfirm transaction worked?
How to improve QPS
(0.7~5ms) SELECT ; (47ms~250ms) insert ; (48ms~250ms) delete
why insert and delete need large time? how to tune insert and delete sql?
I want to add a column to a mysql table where its cells will get values like:
newColumn
-----------
log-00001
log-00002
log-00003
....
the values log-0000x will automatically be created by mysql. This is like an "auto incremented" column but with the 'log-' prefix. Is this possible?
Thx
MySQL doesn't auto-increment anything other than integers. You can't auto-increment a string.
You can't use a trigger to populate a string based on the auto-increment value. The reason is that the auto-increment value isn't generated yet at the time "before" triggers execute, and it's too late to change columns in "after" triggers.
See also my answer to https://stackoverflow.com/a/26899091/20860
You can't use a virtual column, probably for the same reason.
mysql> create table t (id int(5) zerofill auto_increment primary key,
virtcolumn char(8) as (concat('log-', id)));
ERROR 3109 (HY000): Generated column 'virtcolumn' cannot refer to auto-increment column.
You'll have to let the integer auto-increment, and then subsequently use UPDATE to populate your "log-nnnnnn" string after the insert is done.
CREATE TABLE `t` (
`id` int(5) unsigned zerofill NOT NULL AUTO_INCREMENT,
`log` char(9) DEFAULT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `t` () VALUES ();
UPDATE `t` SET `log` = CONCAT('log-', `id`) WHERE `id` = LAST_INSERT_ID();
SELECT * FROM `t`;
+-------+-----------+
| id | log |
+-------+-----------+
| 00001 | log-00001 |
+-------+-----------+
In MySQL (MariaDB actually) I have the following table:
table1:
id | val1 | val2 | val3 | val4 | val5
----------------------------------------------------
I am trying to copy val3 to val1 with the following statement:
UPDATE table1 SET val1=val3 where id=some_id;
The UPDATE command works but takes WAY too long, it takes 813 seconds for 15 Million rows. I have ~200 Billion rows to update, so it will take FOREVER...I think about 118 days.
Any tricks / suggestions on how to do this faster?
SHOW CREATE TABLE table1;
CREATE TABLE `table1` (
`id` int(10) unsigned NOT NULL,
`val1` smallint(5) unsigned NOT NULL,
`val2` mediumint(7) unsigned NOT NULL,
`val3` smallint(5) unsigned NOT NULL,
`val4` binary(1) NOT NULL DEFAULT '\0',
`val5` float DEFAULT NULL,
PRIMARY KEY (`id`,`val1`,`val2`,`val3`)
) ENGINE=TokuDB DEFAULT CHARSET=latin1 `COMPRESSION`=TOKUDB_LZMA
Update this column would make the entire row to be rewritten. It would demand time and it would be IO expensive. Two options:
Use a ternary condition while selecting data: Select IF(some_id =id, val3, val1)...
Split your query among different updates: update table set val1=val3 where id=some_id and val1<>val3 and id>=x and id<= x+1000000. If you can run the same query using different x's (1,1000001,2000001,...) it would make better use of your server cores, instead of using a single one. And once one of those queries end you would know that this part of the job is done. Your bottleneck will be IO and the number of cores you will be able to use.
2.1. Important point: in order to rewrite the least as possible, please make sure that you only update if val1<>val3
Try dropping the primary key, and replacing it with a non-unique index on the id field (this is needed to make the WHERE clause efficient). Do all the updates. Then remove the id index and add back the primary key.
ALTER TABLE table1 DROP PRIMARY KEY, ADD KEY (id);
do all the updates
ALTER TABLE table1 DROP KEY(id), ADD PRIMARY KEY(id, value1, value2, value3);
Scenario:
I have a table which references two foreign keys, and for each unique combination of these foreign keys, has its own auto_increment column. I need to implement a Composite Key that will help identify the row as unique using combination of these three (one foreign keys and one auto_increment column, and one other column with non-unique values)
Table:
CREATE TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT ,
`app_id` INT NOT NULL ,
`test_id` INT NOT NULL ,
`issue_name` VARCHAR(255) NOT NULL ,
primary key (app_id, test_id,sr_no)
);
Of course, there has to be something wrong with my query, because of which the error thrown is:
ERROR 1075: Incorrect table definition; there can be only one auto
column and it must be defined as a key
What I am trying to achieve:
I have an Application Table (with app_id as its primary key), each Application has a set of Issues to be resolved, and each Application has multiple number of tests (so the test_id col)
The sr_no col should increment for unique app_id and test_id.
i.e. The data in table should look like:
The database engine is InnoDB.
I want to achieve this with as much simplicity as possible (i.e. avoid triggers/procedures if possible - which was suggested for similar cases on other Questions).
You can't have MySQL do this for you automatically for InnoDB tables - you would need to use a trigger or procedure, or user another DB engine such as MyISAM. Auto incrementing can only be done for a single primary key.
Something like the following should work
DELIMITER $$
CREATE TRIGGER xxx BEFORE INSERT ON issue_log
FOR EACH ROW BEGIN
SET NEW.sr_no = (
SELECT IFNULL(MAX(sr_no), 0) + 1
FROM issue_log
WHERE app_id = NEW.app_id
AND test_id = NEW.test_id
);
END $$
DELIMITER ;
You can do this with myISAM and BDB engines. InnoDB does not support this. Quote from MySQL 5.0 Reference Manual.
For MyISAM and BDB tables you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix.
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
I don't fully understand your increment requirement on the test_id column, but if you want an ~autoincrement sequence that restarts on every unique combination of (app_id, test_id), you can do an INSERT ... SELECT FROM the same table, like so:
mysql> INSERT INTO `issue_log` (`sr_no`, `app_id`, `test_id`, `issue_name`) SELECT
IFNULL(MAX(`sr_no`), 0) + 1 /* next sequence number */,
3 /* desired app_id */,
1 /* desired test_id */,
'Name of new row'
FROM `issue_log` /* specify the table name as well */
WHERE `app_id` = 3 AND `test_id` = 1 /* same values as in inserted columns */
This assumes a table definition with no declared AUTO_INCREMENT column. You're essentially emulating autoincrement behavior with the IFNULL(MAX()) + 1 clause, but the manual emulation works on arbitrary columns, unlike the built-in autoincrement.
Note that the INSERT ... SELECT being a single query ensures atomicity of the operation. InnoDB will gap-lock the appropriate index, and many concurrent processes can execute this kind of query while still producing non-conflicting sequences.
You can use a unique composite key for sr_no,app_id & test_id. You cannot use incremental in sr_no as this is not unique.
CREATE TABLE IF NOT EXISTS `issue_log` (
`sr_no` int(11) NOT NULL,
`app_id` int(11) NOT NULL,
`test_id` int(11) NOT NULL,
`issue_name` varchar(255) NOT NULL,
UNIQUE KEY `app_id` (`app_id`,`test_id`,`sr_no`)
) ENGINE=InnoDB ;
I have commented out unique constraint violation in sql fiddle to demonstrate (remove # in line 22 of schema and rebuild schema )
This is what I wanted
id tenant
1 1
2 1
3 1
1 2
2 2
3 2
1 3
2 3
3 3
My current table definition is
CREATE TABLE `test_trigger` (
`id` BIGINT NOT NULL,
`tenant` varchar(255) NOT NULL,
PRIMARY KEY (`id`,`tenant`)
);
I created one table for storing the current id for each tenant.
CREATE TABLE `get_val` (
`tenant` varchar(255) NOT NULL,
`next_val` int NOT NULL,
PRIMARY KEY (`tenant`,`next_val`)
) ENGINE=InnoDB ;
Then I created this trigger which solve my problem
DELIMITER $$
CREATE TRIGGER trigger_name
BEFORE INSERT
ON test_trigger
FOR EACH ROW
BEGIN
UPDATE get_val SET next_val = next_val + 1 WHERE tenant = new.tenant;
set new.id = (select next_val from get_val where tenant=new.tenant);
END$$
DELIMITER ;
This approach will be thread safe also because any insertion for the same tenant will happen sequentially because of the update query in the trigger and for different tenants insertions will happen parallelly.
Just add key(sr_no) on auto-increment column:
CREATE TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT ,
`app_id` INT NOT NULL ,
`test_id` INT NOT NULL ,
`issue_name` VARCHAR(255) NOT NULL ,
primary key (app_id, test_id,sr_no),
key (`sr_no`)
);
Why don't you try to change the position of declare fields as primary key, since when you use "auto_increment" it has to be referenced as the first. Like in the following example
CREATE TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT ,
`app_id` INT NOT NULL ,
`test_id` INT NOT NULL ,
`issue_name` VARCHAR(255) NOT NULL ,
primary key (sr_no,app_id, test_id)
);