MySQL MyISAM - not able to add a new column to table - mysql

I have the following table:
mysql> show create table keyword_links\G
*************************** 1. row ***************************
Table: keyword_links
Create Table: CREATE TABLE `keyword_links` (
`keyword_id` int(11) NOT NULL AUTO_INCREMENT,
`keyword` tinytext NOT NULL,
`link` tinytext,
`weight` smallint(6) NOT NULL DEFAULT '0',
`class_id` smallint(6) NOT NULL DEFAULT '0',
`category_id` smallint(6) NOT NULL DEFAULT '0',
`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`keyword_id`),
KEY `class_id` (`class_id`),
KEY `category_id` (`category_id`),
KEY `idx_keyword` (`keyword`(333))
) ENGINE=MyISAM AUTO_INCREMENT=5082 DEFAULT CHARSET=utf8
to which I am trying to add a new column, which is failing:
mysql> ALTER TABLE keyword_links ADD COLUMN list_id INT UNSIGNED NOT NULL DEFAULT 0;
ERROR 1170 (42000): BLOB/TEXT column 'keyword' used in key specification without a key length
The index on keyword column does have a key length of 333, so why is it failing and how to fix it?
UPDATE
I tried reducing the size of the index on the keyword column from 333 to 255 and now I am able to add the new column successfully:
ALTER TABLE keyword_links DROP INDEX idx_keyword;
CREATE INDEX index_keyword ON keyword_links (keyword(255));
ALTER TABLE keyword_links ADD COLUMN list_id INT UNSIGNED NOT NULL DEFAULT 0;
But I would still like to know what's going on.

This is because of myisam's index's length limit of 1000 bytes (see this link)
Please note that this is all about bytes, and that a character might take 2, 3 or even 4 bytes depending on your encoding, and also that an INT will always be 4 bytes.

Index key will allow only 255 i assume.

Related

MySql: AUTO_INCREMENT is missing from tables

MySql: AUTO_INCREMENT is missing from some tables after running for about one month.
Initially: (show create table Foo)
CREATE TABLE `Foo` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`type` tinyint(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8
After one month:
CREATE TABLE `Foo` (
`id` bigint(20) NOT NULL,
`name` varchar(10) NOT NULL,
`type` tinyint(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
AUTO_INCREMENT is missing. What is the cause?
Mysql Server version: 5.6.25, Linux
Someone must have changed it. This change does not happen spontaneously.
I can reproduce this change myself:
CREATE TABLE Foo ( id BIGINT AUTO_INCREMENT, ...
ALTER TABLE Foo MODIFY COLUMN id BIGINT;
SHOW CREATE TABLE Foo\G
*************************** 1. row ***************************
Table: foo
Create Table: CREATE TABLE `foo` (
`id` bigint(20) NOT NULL,
`name` varchar(10) NOT NULL,
`type` tinyint(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Now the column shows it is BIGINT but not AUTO_INCREMENT.
Every time you MODIFY COLUMN or CHANGE COLUMN, you must repeat all the column options like NOT NULL and AUTO_INCREMENT and DEFAULT, or else it will revert to defaults (i.e. not auto-increment).
So I would interpret this shows that someone did an ALTER TABLE and didn't remember to include the AUTO_INCREMENT column option.
Just a thought.
If you have binary logs, you may see the alter query on the logs and when it was run. :)
Check if the binary log is enabled by
show variable like 'log_bin';
If binary log is enabled, find the likely period that the query could have been executed and then use mysqlbinlog to help you find it.
If binary log is not enabled, bad luck - as the previous post by Bill Karwin has suggested mysql does not change it on its own - someone must have changed it.

SQLError:Can't DROP Index_name; check that column/key exists -- occurs multiple times

I want to execute a alter command on a table, create table and alter table commands are as below.
CREATE TABLE `xyz` (
`entity_id` int(11) NOT NULL AUTO_INCREMENT,
`masterform_id` int(11) NOT NULL DEFAULT '1',
`app_status` varchar(500) DEFAULT NULL,
`NegativeMarks` decimal(15,5) DEFAULT NULL,
`ActualScore` decimal(15,5) DEFAULT NULL,
`RawScore` decimal(15,5) DEFAULT NULL,
`PANProratedMarks` decimal(15,5) DEFAULT NULL,
`PANNormalizedMarks` decimal(15,5) DEFAULT NULL,
`RRBZoneNormalizedMarks` decimal(15,5) DEFAULT NULL,
`RRBZoneProratedMarks` decimal(15,5) DEFAULT NULL,
`RRBZoneAllocationTempStorage` varchar(200) DEFAULT NULL,
`GraduatePercentage` decimal(15,5) DEFAULT NULL,
`PANAllocationTempStorage` varchar(1500) DEFAULT NULL,
PRIMARY KEY (`entity_id`),
UNIQUE KEY `app_seq_no` (`app_seq_no`),
UNIQUE KEY `ParticipantID` (`ParticipantID`),
UNIQUE KEY `RegistrationNo` (`RegistrationNo`),
KEY `idx_PANNormalizedMarks` (`PANNormalizedMarks`),
KEY `idx_RRBZoneNormalizedMarks` (`RRBZoneNormalizedMarks`)
) ENGINE=InnoDB AUTO_INCREMENT=273252 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
Alter table xyz
modify column ActualScore decimal(15,5),
modify column app_status varchar(500),
add index CalculatedCategory(CalculatedCategory),
modify column GraduatePercentage decimal(15,5),
modify column NegativeMarks decimal(15,5),
modify column PANAllocationTempStorage varchar(1500),
modify column PANNormalizedMarks decimal(15,5),
modify column PANProratedMarks decimal(15,5),
drop index idx_ParticipantID,
add unique ParticipantID(ParticipantID),
modify column RawScore decimal(15,5),
drop index idx_RegistrationNo,
add unique RegistrationNo(RegistrationNo),
modify column RRBZoneNormalizedMarks decimal(15,5),
modify column RRBZoneProratedMarks decimal(15,5);
I am getting this error:
SQLError:Can't DROP 'idx_ParticipantID'; check that column/key exists
But I am getting this same 104 times. Could you please let me know why am I getting this error 104 times in log? If the index doesnt exist it should just give the error once, please correct me if I am wrong.
After creating table xyz, you are supposed to create the wanted indexes, one of them is idx_ParticipantID (an index on the column ParticipantID). But you didn't create that one, that's why you can't drop it.
But you can ignore those errors, they have no effect on your database.
I advise you to read here some about indexes.

mysql InnoDB: FOREIGN KEY constraint performance

I have the following InnoDB tables:
CREATE TABLE `vehicle` (
`ID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(50) DEFAULT NULL,
`Model` varchar(100) DEFAULT NULL,
`Engine_Type` varchar(70) DEFAULT NULL,
`Construction_From` date DEFAULT NULL,
`Construction_To` date DEFAULT NULL,
`Engine_Power_KW` mediumint(8) unsigned DEFAULT NULL,
`Engine_Power_HP` mediumint(8) unsigned DEFAULT NULL,
`CC` mediumint(8) unsigned DEFAULT NULL,
`TTC_TYP_ID` int(11) unsigned DEFAULT NULL,
`Vehicle_Type` tinyint(1) DEFAULT NULL,
`ID_Body_Type` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=49407 DEFAULT CHARSET=utf8;
CREATE TABLE `part` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ID_Brand` smallint(5) unsigned DEFAULT NULL,
`Code_Full` varchar(50) DEFAULT NULL,
`Code_Condensed` varchar(50) DEFAULT NULL,
`Ean` varchar(50) DEFAULT NULL COMMENT 'The part barcode.',
`TTC_ART_ID` int(11) unsigned DEFAULT NULL COMMENT 'TecDoc ID.',
`ID_Product_Status` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `TTC_ART_ID_UNIQUE` (`TTC_ART_ID`),
UNIQUE KEY `ID_Brand_Code_Full_UNIQUE` (`ID_Brand`,`Code_Full`)
) ENGINE=InnoDB AUTO_INCREMENT=3732260 DEFAULT CHARSET=utf8;
CREATE TABLE `vehicle_part` (
`ID_Vehicle` mediumint(8) unsigned NOT NULL,
`ID_Part` int(11) unsigned NOT NULL,
PRIMARY KEY (`ID_Vehicle`,`ID_Part`),
KEY `fk_vehicle_part_vehicle_id_vehicle_idx` (`ID_Vehicle`),
KEY `fk_vehicle_part_part_id_part_idx` (`ID_Part`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Table vehicle has about 45.000 records, table part has about 3.500.000 records and table vehicle_part has approximately 100.000.000 records.
Creating the secondary indexes for vehicle_part did not take too long, about 30 min for both.
What I cannot do though is create the foreign key constraints: for example
ALTER TABLE `vehicle_part`
ADD CONSTRAINT `fk_vehicle_part_vehicle_id_vehicle`
FOREIGN KEY (`ID_Vehicle`)
REFERENCES `vehicle` (`ID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
takes ages to complete. I understand the table is rebuilt since it consumes a lot of disk space. What can I do to improve the performance?
If I create the table with the fk constraints and then add the records the insert process in vehicle_part also takes ages (about 3 days).
I am using a laptop with 4GB RAM.
EDIT 12/01/2016
The answer given by Drew helped a lot in improving the performance dramatically. I changed every script using SELECT ... INTO outfile and then LOAD DATA INFILE from the exported csv file. Also sometimes before LOAD DATA INFILE dropping the indexes and recreating them after the load proccess saves even more time. There is no need to drop the fk constraints just the secondary indexes.
If you know your data is pristine from an FK perspective, then establish your structure without secondary indexes as suggested in comments, but with the FK in the schema yet with FK checks temporarily disabled.
Load your data. If external data, certainly do it with LOAD DATA INFILE.
After your data is loaded, turn on FK checks. And establish secondary indexes with Alter Table.
Again, going with the assumption that your data is clean. There are other ways of proving that after-the-fact for the risk-adverse.
create table student
( id int auto_increment primary key,
sName varchar(100) not null
-- secondary indexes to be added later
);
create table booksAssigned
( id int auto_increment primary key,
studentId int not null,
isbn varchar(20) not null,
constraint foreign key `fk_b_s` (studentId) references student(id)
-- secondary indexes to be added later
);
insert booksAssigned(studentId,isbn) values (1,'asdf'); -- Error 1452 as expected
set FOREIGN_KEY_CHECKS=0; -- turn FK checks of temporarily
insert booksAssigned(studentId,isbn) values (1,'asdf'); -- Error 1452 as expected
set FOREIGN_KEY_CHECKS=1; -- succeeds despite faulty data
insert booksAssigned(studentId,isbn) values (2,'38383-asdf'); -- Error 1452 as expected
As per op comments, how to drop auto-generated index in referencing table after initial schema creation:
mysql> show create table booksAssigned;
| booksAssigned | CREATE TABLE `booksassigned` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`studentId` int(11) NOT NULL,
`isbn` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_b_s` (`studentId`),
CONSTRAINT `booksassigned_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`)
) ENGINE=InnoDB |
mysql> set FOREIGN_KEY_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)
mysql> drop index `fk_b_s` on booksAssigned;
Query OK, 0 rows affected (0.49 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table booksAssigned;
| booksAssigned | CREATE TABLE `booksassigned` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`studentId` int(11) NOT NULL,
`isbn` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `booksassigned_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `student` (`id`)
) ENGINE=InnoDB |
Further links
Temporarily disable foreign keys
A Rolando Answer

#1071 - Specified key was too long; max key length is 767 bytes

I this SQL query to create a table:
CREATE TABLE IF NOT EXISTS `local_sysDB`.`hashtags` (
`id` INT NOT NULL AUTO_INCREMENT,
`hashtag` VARCHAR(255) NOT NULL COMMENT 'hashtag must be unique. Must be saved without #',
`accountId` INT NULL,
`startTracking` DATETIME NOT NULL COMMENT 'When tracking of the hashtag start',
`endTracking` DATETIME NOT NULL COMMENT 'When tracking of the hashtag ends',
`channelInstagram` TINYINT(1) NOT NULL DEFAULT 1,
`channelTwitter` TINYINT(1) NOT NULL DEFAULT 1,
`channelYoutube` TINYINT(1) NOT NULL DEFAULT 1,
`postLimit` INT NOT NULL,
`suspendOnLimit` TINYINT(1) NOT NULL DEFAULT 1,
`created` TIMESTAMP NOT NULL DEFAULT NOW(),
`updated` TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
`approveBeforeView` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'If account should approve posts before being displayed public',
`suspended` TINYINT(1) NOT NULL DEFAULT 0,
`InstagramSubscriptionId` INT(10) UNSIGNED NULL,
`deleted` TINYINT(1) NULL DEFAULT 0 COMMENT 'if hashtag is marked for deletion',
`collectedPosts` BIGINT(50) UNSIGNED NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE INDEX `hashtags_hashtag` (`hashtag` ASC) KEY_BLOCK_SIZE=255,
INDEX `hashtags_accounts_accountId` (`accountId` ASC),
INDEX `hashtag_trackingDate` (`startTracking` ASC, `endTracking` ASC),
INDEX `hashtag_collectedPosts` (`collectedPosts` ASC),
INDEX `hashtag_updated` (`updated` ASC),
FULLTEXT INDEX `hashtag_search` (`hashtag` ASC),
CONSTRAINT `hashtags_accounts_accountId`
FOREIGN KEY (`accountId`)
REFERENCES `local_sysDB`.`accounts` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
ROW_FORMAT = COMPRESSED
KEY_BLOCK_SIZE = 16;
When I try to run this, I get the following error:
SQL-query:
CREATE TABLE IF NOT EXISTS `local_sysDB`.`hashtags` (
`id` INT NOT NULL AUTO_INCREMENT,
`hashtag` VARCHAR(255) NOT NULL COMMENT 'hashtag must be unique. Must be saved without #',
`accountId` INT NULL,
`startTracking` DATETIME NOT NULL COMMENT 'When tracking of the hashtag start',
`endTracking` DATETIME NOT NULL COMMENT 'When tracking of the hashtag ends',
`channelInstagram` TINYINT(1) NOT NULL DEFAULT 1,
`channelTwitter` TINYINT(1) NOT NULL DEFAULT 1,
`channelYoutube` TINYINT(1) NOT NULL DEFAULT 1,
`postLimit` INT NOT NULL,
`suspendOnLimit` TINYINT(1) NOT NULL DEFAULT 1,
`created` TIMESTAMP NOT NULL DEFAULT NOW(),
`updated` TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
`approveBeforeView` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'If account should approve posts before being displayed public',
`suspended` TINYINT(1) NOT NULL DEFAULT 0,
`InstagramSubscriptionId` INT(10) UNSIGNED NULL,
`deleted` TINYINT(1) NULL DEFAULT 0 COMMENT 'if hashtag is [...]
MySQL meldt: Documentatie
#1071 - Specified key was too long; max key length is 767 bytes
I already found out it has something to do with this:
767 bytes is the stated prefix limitation for InnoDB tables - its
1,000 bytes long for MyISAM tables.
According to the response to this issue, you can get the key to apply
by specifying a subset of the column rather than the entire amount.
IE:
ALTER TABLE mytable ADD UNIQUE ( column1(15), column2(200) ); Tweak
as you need to get the key to apply, but I wonder if it would be worth
it to review your data model regarding this entity to see if there's
improvements that would allow you to implement the intended business
rules without hitting the MySQL limitation.
I tried adding a length to my indexes, but MySQL Workbench keeps resetting them to 0.
I'd like to know if there could be another cause of this problem, or another way to solve this problem.
I just learned a workaround... Get 5.5.14 or 5.6.3 (or later), do the SETs indicated here, and use DYNAMIC or COMPRESSED:
SET GLOBAL innodb_file_per_table = ON,
innodb_file_format = Barracuda,
innodb_large_prefix = ON;
CREATE TABLE so29676724 (
`id` INT NOT NULL AUTO_INCREMENT,
`hashtag` VARCHAR(255) NOT NULL COMMENT 'hashtag must be unique. Must be saved without #',
PRIMARY KEY (`id`),
UNIQUE INDEX `hashtags_hashtag` (`hashtag` ASC)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET utf8mb4
ROW_FORMAT = COMPRESSED;
SHOW CREATE TABLE so29676724\G
mysql> CREATE TABLE so29676724 (
-> `id` INT NOT NULL AUTO_INCREMENT,
-> `hashtag` VARCHAR(255) NOT NULL COMMENT 'hashtag must be unique. Must be saved without #',
-> PRIMARY KEY (`id`),
-> UNIQUE INDEX `hashtags_hashtag` (`hashtag` ASC)
-> )
-> ENGINE = InnoDB
-> DEFAULT CHARACTER SET utf8mb4
-> ROW_FORMAT = COMPRESSED;
Query OK, 0 rows affected (0.09 sec)
"Hashes" are usually hex, not UTF-8. Hashes are usually much shorter than 255.
If either applies, then...
`hashtag`
VARCHAR(160) -- this
CHARACTER SET ascii -- and/or this
would be a solution that would work on any version without any of the innodb settings indicated.
(Note: 191 is the cutoff for VARCHAR with utf8mb4, but few standard hashes need that much.)

How to drop composite UNIQUE KEY in MySQL?

This question has been asked before, but they all referenced to single and not composite keys, and the solutions don't seem to work for me. Basically, please consider the following table:
CREATE TABLE IF NOT EXISTS `my_answers` (
`id` int(11) NOT NULL auto_increment,
`question_id` int(11) NOT NULL default 0,
`user_id` int(11) NOT NULL default 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`question_id`, `user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
How do I remove the unique key made of question_id and user_id in this case? I have tried the following:
ALTER TABLE my_answers DROP INDEX `UNIQUE`;
and
DROP INDEX UNIQUE ON my_answers;
Both of which didn't work, throwing the following error "#1091 - Can't DROP 'UNIQUE'; check that column/key exists"
Any help is greatly appreciated, thanks!
If you do not specify a name of the unique key in case of composite key then by default the first column name is used as the name.
Here is the example
mysql> CREATE TABLE IF NOT EXISTS `my_answers` (
-> `id` int(11) NOT NULL auto_increment,
-> `question_id` int(11) NOT NULL default 0,
-> `user_id` int(11) NOT NULL default 0,
-> PRIMARY KEY (`id`),
-> UNIQUE KEY (`question_id`, `user_id`)
-> ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.08 sec)
If you now run show create table you can see something as
mysql> show create table my_answers ;
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| my_answers | CREATE TABLE `my_answers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`question_id` int(11) NOT NULL DEFAULT '0',
`user_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `question_id` (`question_id`,`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
Here you can see that the key name is the first column in the composite key which is question_id and you can drop it as
mysql> alter table `my_answers` drop INDEX question_id ;
Query OK, 0 rows affected (0.09 sec)
Try the following command:
show index from `my_answers`;
then inspect the key name of your index and drop it by its name.
I have found the answer, turns out it was ridiculously simple. Simply remove one of the field as index key:
ALTER TABLE my_answers DROP INDEX user_id
Turns out this will dismantle the composite key.