MySQL error: The maximum column size is 767 bytes - mysql

When I run a program which does something with MySQL, I got this error message:
2015-06-10 15:41:12,250 ERROR app.wsutils 419 INCRON: Error: ('HY000',
'[HY000] [MySQL][ODBC 5.2(w) Driver][mysqld-5.7.7-rc-log]Index column
size too large. The maximum column size is 767 bytes. (1709)
(SQLExecDirectW)')
I Googled a little bit and found this error might be related to the innodb_large_prefix option. However, I am using MySQL 5.7.7 RC, which has already set innodb_large_prefix to be "ON" (checked in MySQL Workbench), allowing up to 3072 bytes. I am not sure if that is the problem with innodb_large_prefix or not.
Anyway, does anyone have an idea how to fix this problem?

From Wamp Version 3.2.6
Just edit this file:
C:\wamp64\bin\mysql\mysql8.0.27\my.ini
Change the config for innodb-default-row-format value
from innodb-default-row-format=compact
to innodb-default-row-format=dynamic
Restart mysql

With the help of the answer given by BK435, I did the following and solved the problem.
set global innodb_file_format = BARRACUDA;
set global innodb_large_prefix = ON;
create table test (........) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

Your column that you are trying to index is too large and your settings must not be correct for innodb_large_prefix. There are a couple prerequisites parameters that also have to be set in order for innodb_large_prefix to work correctly.
You can check to make sure that innodb_large_prefix is set by running:
show global variables like 'innodb_lar%';
Here are a couple prerequisites for using innodb_large_prefix:
You need to set your global variable innodb_file_format=BARRACUDA
to check settings run: show global variables like 'innodb_fil%';
At the table level you have to use ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED
for Innodb, rows are stored in COMPACT format (ROW_FORMAT=COMPACT) by default.

I was using MariaDB version 10.1.38 and used all of the below given commands but it did not work -
set global innodb_large_prefix = ON;
Query OK, 0 rows affected (0.00 sec)
set global innodb_file_per_table = ON;
Query OK, 0 rows affected (0.00 sec)
set global innodb_file_format = Barracuda;
Query OK, 0 rows affected (0.00 sec)
SET GLOBAL innodb_default_row_format = 'DYNAMIC';
Because after you restart your MySQL (or MariaDB), these settings will not reflect back using the command at the mysql prompt: show variables like 'innodb%';
Then I edited My.ini and added these settings in the file at below location-
C:\xampp\mysql\bin\my.ini
## Innodb settings to bypass error of max size 737
innodb-file-format=barracuda
innodb-file-per-table=ON
innodb-large-prefix=ON
## Above 3 didnot work so i added below
innodb_default_row_format = 'DYNAMIC'
source:https://www.experts-exchange.com/questions/28675824/Why-am-I-unable-to-turn-innodb-large-prefix-ON-successfully-Every-time-I-reboot-mySql-on-my-Ubuntu-VPS-it-resets-to-OFF.html

For me using Mariadb 10.1.31, just add this while you login in Mysql CLI:
SET GLOBAL innodb_file_format = Barracuda;
SET GLOBAL innodb_file_per_table = ON;
SET GLOBAL innodb_large_prefix = ON;
SET GLOBAL innodb_default_row_format = 'DYNAMIC';

Just add the following options to my.cnf
[mysqld]
innodb_file_format=Barracuda
innodb_file_per_table=1
innodb_large_prefix=1
Then, restart mysql server the problem will be resolved.

You need to change the innodb-default-row-format variable to dynamic.
If you are using phpMyAdmin, navigate to variables and search for row format.
If you are using WampServer, navigate to my.ini file like:
C:\wamp64\bin\mysql\mysql8.0.27\my.ini
For more info, visit MySQL Manual

This worked for me:
From Wamp Version 3.2.6
Just edit this file: C:\wamp64\bin\mysql\mysql8.0.27\my.ini
Change the config for innodb-default-row-format value
from innodb-default-row-format=compact
to innodb-default-row-format=dynamic
Restart mysql

Go to mysql config in this file my.cnf
change this line
innodb-default-row-format=compact
to
innodb-default-row-format=dynamic

I had the same error despite having innodb_large_prefix configured correctly.
The issue was in used collation. My db had default collation set to utf8mb4_bin (you can check it in phpmyadmin "Operations" tab for database). It means it uses 4 bytes per char, while utf8 collation (e.g. utf8_unicode_ci) uses 3 bytes per char.
in this case you can either use different collation e.g. by adding DEFAULT CHARSET=utf8 at the end of the CREATE TABLE statement, or limit the index size by using just a part of the column value
like KEY 'identifier' (column1(5),column2(10)).
See also related question: #1071 - Specified key was too long; max key length is 767 bytes

In my case (MySQL version 5.6) the issue was that I was trying to create a table with a column that can have up to 256 characters (the db uses utf8 collation), so 3 bytes per 1 utf8 character = 256*3=768 bytes. The fix was to simply have 255 characters instead of 256.
I could also set innodb_large_prefix, like others suggest, but in my case it was easier to just have fewer symbols.

Just like #sasank-mukkamala said , for me only adding ROW_FORMAT=DYNAMIC to create command did it rightly.
create table `NameOfTheTable` (........) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

Im using Mysql 5.7
Click PHPMyAdmin (home)
Click Variables
On innodb default row formart, click edit then enter 2, then click save
It will show variable value as dynamic
Import table again

I had this problem because I tried to create a String primary key with varchar(254). Easy to overlook sometimes.. So double check your index type and length as well :)

In case someone is working with MySQL 5.6 the only solution that I found was to update to MySQL 5.7 and setting my.cnf as mentioned in previous comments (https://stackoverflow.com/a/57465002/2300390).

I had the same error but on a different issue. I got this error while importing a data (data and schema) script. Deleting the Unique Index fixed the issue for me.
Answer taken from this link

Set the below system variables:
innodb_buffer_pool_size.................................... 702545920
innodb_file_format......................................... Barracuda
innodb_file_format_check................................... ON
innodb_file_format_max..................................... Barracuda
innodb_file_per_table...................................... ON
innodb_large_prefix........................................ ON
innodb_log_file_size....................................... 50331648
Also, make sure when you create your schema you create it as Latin1. That is what finally fixed me.

Related

Specified key was too long; max key length is 767 MariaDB 10.1 [duplicate]

When I executed the following command:
ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);
I got this error message:
#1071 - Specified key was too long; max key length is 767 bytes
Information about column1 and column2:
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
I think varchar(20) only requires 21 bytes while varchar(500) only requires 501 bytes. So the total bytes are 522, less than 767. So why did I get the error message?
#1071 - Specified key was too long; max key length is 767 bytes
767 bytes in MySQL version 5.6 (and prior versions), is the stated prefix limitation for InnoDB tables. It's 1,000 bytes long for MyISAM tables. This limit has been increased to 3072 bytes In MySQL version 5.7 (and upwards).
You also have to be aware that if you set an index on a big char or varchar field which is utf8mb4 encoded, you have to divide the max index prefix length of 767 bytes (or 3072 bytes) by 4 resulting in 191. This is because the maximum length of a utf8mb4 character is four bytes. For a utf8 character it would be three bytes resulting in max index prefix length of 255 (or minus null-terminator, 254 characters).
One option you have is to just place lower limit on your VARCHAR fields.
Another option (according to the response to this issue) is to get the subset of the column rather than the entire amount, i.e.:
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 possible, which would allow you to implement the intended business rules without hitting the MySQL limitation.
When you hit the limit. Set the following.
INNODB utf8 VARCHAR(255)
INNODB utf8mb4 VARCHAR(191)
If anyone is having issues with InnoDB and utf8 charset trying to put a UNIQUE index on a VARCHAR(256) field, switch it to VARCHAR(255). It seems 255 is the limitation.
MySQL assumes worst case for the number of bytes per character in the string. For the MySQL 'utf8' encoding, that's 3 bytes per character since that encoding doesn't allow characters beyond U+FFFF. For the MySQL 'utf8mb4' encoding, it's 4 bytes per character, since that's what MySQL calls actual UTF-8.
So assuming you're using 'utf8', your first column will take 60 bytes of the index, and your second another 1500.
Solution For Laravel Framework
As per Laravel 5.4.* documentation; You have to set the default string length inside the boot method of the app/Providers/AppServiceProvider.php file as follows:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Explanation of this fix, given by Laravel 5.4.* documentation:
Laravel uses the utf8mb4 character set by default, which includes support for storing "emojis" in the database. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the Schema::defaultStringLength method within your AppServiceProvider.
Alternatively, you may enable the innodb_large_prefix option for your
database. Refer to your database's documentation for instructions on
how to properly enable this option.
run this query before your query:
SET ##global.innodb_large_prefix = 1;
this will increase limit to 3072 bytes.
What character encoding are you using? Some character sets (like UTF-16, et cetera) use more than one byte per character.
Replace utf8mb4 with utf8 in your import file.
But note that utf8 charset is deprecated and it does not support all Unicode characters, e.g. emojis, so you will lose full Unicode support if you do this.
I think varchar(20) only requires 21 bytes while varchar(500) only
requires 501 bytes. So the total bytes are 522, less than 767. So why
did I get the error message?
UTF8 requires 3 bytes per character to store the string, so in your case 20 + 500 characters = 20*3+500*3 = 1560 bytes which is more than allowed 767 bytes.
The limit for UTF8 is 767/3 = 255 characters, for UTF8mb4 which uses 4 bytes per character it is 767/4 = 191 characters.
There are two solutions to this problem if you need to use longer column than the limit:
Use "cheaper" encoding (the one that requires less bytes per character)
In my case, I needed to add Unique index on column containing SEO string of article, as I use only [A-z0-9\-] characters for SEO, I used latin1_general_ci which uses only one byte per character and so column can have 767 bytes length.
Create hash from your column and use unique index only on that
The other option for me was to create another column which would store hash of SEO, this column would have UNIQUE key to ensure SEO values are unique. I would also add KEY index to original SEO column to speed up look up.
The answer about why you get error message was already answered by many users here. My answer is about how to fix and use it as it be.
Refer from this link.
Open MySQL client (or MariaDB client). It is a command line tool.
It will ask your password, enter your correct password.
Select your database by using this command use my_database_name;
Database changed
set global innodb_large_prefix=on;
Query OK, 0 rows affected (0.00 sec)
set global innodb_file_format=Barracuda;
Query OK, 0 rows affected (0.02 sec)
Go to your database on phpMyAdmin or something like that for easy management. > Select database > View table structure > Go to Operations tab. > Change ROW_FORMAT to DYNAMIC and save changes.
Go to table's structure tab > Click on Unique button.
Done. Now it should has no errors.
The problem of this fix is if you export db to another server (for example from localhost to real host) and you cannot use MySQL command line in that server. You cannot make it work there.
Specified key was too long; max key length is 767 bytes
You got that message because 1 byte equals 1 character only if you use the latin-1 character set. If you use utf8, each character will be considered 3 bytes when defining your key column. If you use utf8mb4, each character will be considered to be 4 bytes when defining your key column. Thus, you need to multiply your key field's character limit by, 1, 3, or 4 (in my example) to determine the number of bytes the key field is trying to allow. If you are using uft8mb4, you can only define 191 characters for a native, InnoDB, primary key field. Just don't breach 767 bytes.
5 workarounds:
The limit was raised in 5.7.7 (MariaDB 10.2.2?). And it can be increased with some work in 5.6 (10.1).
If you are hitting the limit because of trying to use CHARACTER SET utf8mb4. Then do one of the following (each has a drawback) to avoid the error:
⚈ Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
⚈ Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
⚈ ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
⚈ Use a "prefix" index -- you lose some of the performance benefits.
⚈ Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC; -- (or COMPRESSED)
-- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
you could add a column of the md5 of long columns
For laravel 5.7 to 9.0
Steps to followed
Go to App\Providers\AppServiceProvider.php.
Add this to provider use Illuminate\Support\Facades\Schema; in top.
Inside the Boot function Add this Schema::defaultStringLength(191);
that all, Enjoy.
We encountered this issue when trying to add a UNIQUE index to a VARCHAR(255) field using utf8mb4. While the problem is outlined well here already, I wanted to add some practical advice for how we figured this out and solved it.
When using utf8mb4, characters count as 4 bytes, whereas under utf8, they could as 3 bytes. InnoDB databases have a limit that indexes can only contain 767 bytes. So when using utf8, you can store 255 characters (767/3 = 255), but using utf8mb4, you can only store 191 characters (767/4 = 191).
You're absolutely able to add regular indexes for VARCHAR(255) fields using utf8mb4, but what happens is the index size is truncated at 191 characters automatically - like unique_key here:
This is fine, because regular indexes are just used to help MySQL search through your data more quickly. The whole field doesn't need to be indexed.
So, why does MySQL truncate the index automatically for regular indexes, but throw an explicit error when trying to do it for unique indexes? Well, for MySQL to be able to figure out if the value being inserted or updated already exists, it needs to actually index the whole value and not just part of it.
At the end of the day, if you want to have a unique index on a field, the entire contents of the field must fit into the index. For utf8mb4, this means reducing your VARCHAR field lengths to 191 characters or less. If you don't need utf8mb4 for that table or field, you can drop it back to utf8 and be able to keep your 255 length fields.
I fixed this issue with :
varchar(200)
replaced with
varchar(191)
all the unique or primary varchar keys which have more than 200 replace them with 191 or set them as text.
Here is my original answer:
I just drop database and recreate like this, and the error is gone:
drop database if exists rhodes; create database rhodes default
CHARACTER set utf8 default COLLATE utf8_general_ci;
However, it doesn't work for all the cases.
It is actually a problem of using indexes on VARCHAR columns with the character set utf8 (or utf8mb4), with VARCHAR columns that have more than a certain length of characters. In the case of utf8mb4, that certain length is 191.
Please refer to the Long Index section in this article for more information how to use long indexes in MySQL database: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-character-set-to-utf8mb4
To fix that, this works for me like a charm.
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
I did some search on this topic finally got some custom change
For MySQL workbench 6.3.7 Version Graphical inter phase is available
Start Workbench and select the connection.
Go to management or Instance and select Options File.
If Workbench ask you permission to read configuration file and then allow it by pressing OK two times.
At center place Administrator options file window comes.
Go To InnoDB tab and check the innodb_large_prefix if it not checked in the General section.
set innodb_default_row_format option value to DYNAMIC.
For Versions below 6.3.7 direct options are not available so need to go with command prompt
Start CMD as administrator.
Go To director where mysql server is install Most of cases its at
"C:\Program Files\MySQL\MySQL Server 5.7\bin" so command is
"cd \"
"cd Program Files\MySQL\MySQL Server 5.7\bin".
Now Run command
mysql -u userName -p databasescheema
Now it asked for password of respective user.
Provide password and enter into mysql prompt.
We have to set some global settings enter the below commands one by one
set global innodb_large_prefix=on;
set global innodb_file_format=barracuda;
set global innodb_file_per_table=true;
Now at the last we have to alter the ROW_FORMAT of required table by default its COMPACT we have to set it to DYNAMIC.
use following command
alter table table_name ROW_FORMAT=DYNAMIC;
Done
change your collation. You can use utf8_general_ci that supports almost all
Just changing utf8mb4 to utf8 when creating tables solved my problem. For example: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; to CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.
Index Lengths & MySQL / MariaDB
Laravel uses the utf8mb4 character set by default, which includes support for storing "emojis" in the database. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the Schema::defaultStringLength method within your AppServiceProvider:
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
Alternatively, you may enable the innodb_large_prefix option for your database. Refer to your database's documentation for instructions on how to properly enable this option.
Reference from blog : https://www.scratchcode.io/specified-key-too-long-error-in-laravel/
Reference from Official laravel documentation : https://laravel.com/docs/5.7/migrations
This solved my issue
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Based on the column given below, those 2 variable string columns are using utf8_general_ci collation (utf8 charset is implied).
In MySQL, utf8 charset uses a maximum of 3 bytes for each character. Thus, it would need to allocate 500*3=1500 bytes, which is much greater than the 767 bytes MySQL allows. That's why you are getting this 1071 error.
In other words, you need to calculate the character count based on the charset's byte representation as not every charset is a single byte representation (as you presumed.) I.E. utf8 in MySQL is uses at most 3-byte per character, 767/3≈255 characters, and for utf8mb4, an at most 4-byte representation, 767/4≈191 characters.
It's also known that MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
In my case, I had this problem when I was backing up a database using the linux redirection output/input characters. Therefore, I change the syntax as described below. PS: using a linux or mac terminal.
Backup (without the > redirect)
# mysqldump -u root -p databasename -r bkp.sql
Restore (without the < redirect )
# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql
The error "Specified key was too long; max key length is 767 bytes" simple disappeared.
I found this query useful in detecting which columns had an index violating the max length:
SELECT
c.TABLE_NAME As TableName,
c.COLUMN_NAME AS ColumnName,
c.DATA_TYPE AS DataType,
c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
ON s.table_name = c.TABLE_NAME
AND s.COLUMN_NAME = c.COLUMN_NAME
WHERE c.TABLE_SCHEMA = DATABASE()
AND c.CHARACTER_MAXIMUM_LENGTH > 191
AND c.DATA_TYPE IN ('char', 'varchar', 'text')
Please check if sql_mode is like
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
if it is, change to
sql_mode=NO_ENGINE_SUBSTITUTION
OR
restart your server changing your my.cnf file (putting following)
innodb_large_prefix=on
Due to prefix limitations this error will occur. 767 bytes is the stated prefix limitation for InnoDB tables in MySQL versions before 5.7 . It's 1,000 bytes long for MyISAM tables. In MySQL version 5.7 and upwards this limit has been increased to 3072 bytes.
Running the following on the service giving you the error should resolve your issue. This has to be run in the MYSQL CLI.
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;
The Problem
There are max key length limits in MySQL.
InnoDB — max key length is 1,536 bytes (for 8kb page size) and 768 (for 4kb page size) (Source: Dev.MySQL.com).
MyISAM — max key length is 1,000 bytes (Source Dev.MySQL.com).
These are counted in bytes! So, a UTF-8 character may take more than one byte to be stored into the key.
Therefore, you have only two immediate solutions:
Index only the first n'th characters of the text type.
Create a FULL TEXT search — Everything will be Searchable within the Text, in a fashion similar to ElasticSearch
Indexing the First N'th Characters of a Text Type
If you are creating a table, use the following syntax to index some field's first 255 characters: KEY sometextkey (SomeText(255)). Like so:
CREATE TABLE `MyTable` (
`id` int(11) NOT NULL auto_increment,
`SomeText` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `sometextkey` (`SomeText`(255))
);
If you already have the table, then you can add a unique key to a field with: ADD UNIQUE(ConfigValue(20));. Like so:
ALTER TABLE
MyTable
ADD UNIQUE(`ConfigValue`(20));
If the name of the field is not a reserved MySQL keyword, then the backticks (```) are not necessary around the fieldname.
Creating a FULL TEXT Search
A Full Text search will allow you to search the entirety of the value of your TEXT field. It will do whole-word matching if you use NATURAL LANGUAGE MODE, or partial word matching if you use one of the other modes. See more on the options for FullText here: Dev.MySQL.com
Create your table with the text, and add the Full text index...
ALTER TABLE
MyTable
ADD FULLTEXT INDEX
`SomeTextKey` (`SomeTextField` DESC);
Then search your table like so...
SELECT
MyTable.id, MyTable.Title,
MATCH
(MyTable.Text)
AGAINST
('foobar' IN NATURAL LANGUAGE MODE) AS score
FROM
MyTable
HAVING
score > 0
ORDER BY
score DESC;
I have changes from varchar to nvarchar, works for me.

SQL_MODE and TIME_ZONE when creating DATABASE

What do these options mean, and what are the possible choices when creating the database?
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
#------------------------------------------------------------
# Script MySQL.
#------------------------------------------------------------
DROP DATABASE if exists BASETEST;
CREATE DATABASE IF NOT EXISTS BASETEST DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI;
USE BASETEST;
SET set's one of MySQL variables. Some of them are system variables some of them are user variables ...
SET SQL_MODE:
SQL_MODE is a system variables and you can see all possible modes in the documentation.
NO_AUTO_VALUE_ON_ZERO :
NO_AUTO_VALUE_ON_ZERO affects handling of AUTO_INCREMENT columns. Normally, you generate the next sequence number for the column by inserting either NULL or 0 into it. NO_AUTO_VALUE_ON_ZERO suppresses this behavior for 0 so that only NULL generates the next sequence number.
SET time_zone :
SET time_zone = "+00:00" Sets the session timezone on UTC.
Read more : How do I set the time zone of MySQL?
The SET statement is used here:
to assign values to variables that affect the operation of the server or clients
Neither the statement nor the variables are specific to database creation. In fact I don't think they should have any noticeable effect:
You cannot configure AUTO_INCREMENT handling in a per database basis (only per server or per session).
A database does not have a time zone (the server or current session do).
It's common though that tools that generate SQL dumps set some variables to configure session and get a predictable environment to run commands. Such variables tend to come from a template and aren't customised for script content.

How to allow empty string for integer in MySQL?

I have integer fields in a table. The POSTs are sent by a complicated JavaScript. They send empty strings like "" but as you guessed MySQL doesn't allow empty strings in integer fields. Are there any options to allow empty strings? Like if it takes an empty string it will save it as NULL.
There are 2 ways to do this.
For Current Mysql Session (Temporary Solution)
First execute query to get current SQL mode of your mysql server.
mysql> SELECT ##sql_mode;
+----------------------------------------------------------------+
| ##sql_mode |
+----------------------------------------------------------------+
|STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
If result contains STRICT_TRANS_TABLES, you have to remove that value to allow insert query to pass NULL value. Make sure your mysql User have privileges to apply this changes and restart Mysql Server after applying this.
SET GLOBAL sql_mode = '';
For Life Time of Mysql (Permanent Solution)
You have to update my.cnf file. Location of that file is : \etc\my.cnf or \etc\mysql\mysql.cnf
There will be some default parameters set under [mysqld] like
[mysqld]
innodb_file_per_table=1
default-storage-engine=MyISAM
performance-schema=0
max_allowed_packet=268435456
open_files_limit=10000
Just add one line under that
sql-mode=""
Make sure to restart Mysql Server after changing this file. Normally root user will be the owner of file so you have to login with root user on server.
For more details to understand what this SQL mode do.
STRICT_TRANS_TABLES
Enable strict SQL mode for transactional storage engines, and when possible for non-transactional storage engines. For details, see Strict SQL Mode.
Refer : http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_trans_tables
NO_AUTO_CREATE_USER
Prevent the GRANT statement from automatically creating new user accounts if it would otherwise do so, unless authentication information is specified. The statement must specify a nonempty password using IDENTIFIED BY or an authentication plugin using IDENTIFIED WITH.
Refer: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_auto_create_user
NO_ENGINE_SUBSTITUTION
Control automatic substitution of the default storage engine when a statement such as CREATE TABLE or ALTER TABLE specifies a storage engine that is disabled or not compiled in.
Refer : http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_engine_substitution
Removing sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" from my.ini has solved the issue.
Edit: Removing the line above works but it is a bad idea. It allows to have things like 0000-00-00 or empty string dates. Better keep the line above and don't insert empty sting into an integer field, instead convert empty string into NULL and then insert that NULL into integer field.
Assuming that the column allows for NULL values, you must explicitly tell MySQL to use a value of NULL, rather than passing an empty string (which is cast to 0):
INSERT INTO table (column_name) VALUES (NULL);

ft_min_word_len set in local my.cnf?

Is it possible to set ft_min_word_len for a certain user (such as by placing a my.cnf file in the user home dir with ft_min_word_len set)? The documentation says I need to restart the server after making this change, but a user does not have access to do that.
I'm working with this now, so to add as a reference for anyone looking at this...
You can use this query in a query
browser or the MySQL prompt to show
the state of ft_min_word_len: "SHOW
VARIABLES LIKE 'ft_min_word_len';"
ft_min_word_len deafults to a value
of '4' and is not by default listed
in "my.cnf". To change it's default
value, add: "ft_min_word_len = 3" to
my.cnf under the [mysqld] section.
After changing the value of
ft_min_word_len, the server must be
restarted.
After changing the value of
ft_min_word_len, any indexes you have
must be rebuilt
A fast way to rebuild an index is to
use this query: "REPAIR TABLE
your_table_name QUICK;" Note:
You're using the name of the table
only, not the name of any indexes.
If you have more than one index
against the 'your_table_name' table,
all of them will be re-built.
No, it's not possible, because it changes how the fulltext indices are built. It takes effect at index generation, not (only) at query time.
FYI: Not only do you have to restart the server, you have to rebuild all your fulltext indices after changing it.

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

When I executed the following command:
ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);
I got this error message:
#1071 - Specified key was too long; max key length is 767 bytes
Information about column1 and column2:
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
I think varchar(20) only requires 21 bytes while varchar(500) only requires 501 bytes. So the total bytes are 522, less than 767. So why did I get the error message?
#1071 - Specified key was too long; max key length is 767 bytes
767 bytes in MySQL version 5.6 (and prior versions), is the stated prefix limitation for InnoDB tables. It's 1,000 bytes long for MyISAM tables. This limit has been increased to 3072 bytes In MySQL version 5.7 (and upwards).
You also have to be aware that if you set an index on a big char or varchar field which is utf8mb4 encoded, you have to divide the max index prefix length of 767 bytes (or 3072 bytes) by 4 resulting in 191. This is because the maximum length of a utf8mb4 character is four bytes. For a utf8 character it would be three bytes resulting in max index prefix length of 255 (or minus null-terminator, 254 characters).
One option you have is to just place lower limit on your VARCHAR fields.
Another option (according to the response to this issue) is to get the subset of the column rather than the entire amount, i.e.:
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 possible, which would allow you to implement the intended business rules without hitting the MySQL limitation.
When you hit the limit. Set the following.
INNODB utf8 VARCHAR(255)
INNODB utf8mb4 VARCHAR(191)
If anyone is having issues with InnoDB and utf8 charset trying to put a UNIQUE index on a VARCHAR(256) field, switch it to VARCHAR(255). It seems 255 is the limitation.
MySQL assumes worst case for the number of bytes per character in the string. For the MySQL 'utf8' encoding, that's 3 bytes per character since that encoding doesn't allow characters beyond U+FFFF. For the MySQL 'utf8mb4' encoding, it's 4 bytes per character, since that's what MySQL calls actual UTF-8.
So assuming you're using 'utf8', your first column will take 60 bytes of the index, and your second another 1500.
Solution For Laravel Framework
As per Laravel 5.4.* documentation; You have to set the default string length inside the boot method of the app/Providers/AppServiceProvider.php file as follows:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Explanation of this fix, given by Laravel 5.4.* documentation:
Laravel uses the utf8mb4 character set by default, which includes support for storing "emojis" in the database. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the Schema::defaultStringLength method within your AppServiceProvider.
Alternatively, you may enable the innodb_large_prefix option for your
database. Refer to your database's documentation for instructions on
how to properly enable this option.
run this query before your query:
SET ##global.innodb_large_prefix = 1;
this will increase limit to 3072 bytes.
What character encoding are you using? Some character sets (like UTF-16, et cetera) use more than one byte per character.
Replace utf8mb4 with utf8 in your import file.
But note that utf8 charset is deprecated and it does not support all Unicode characters, e.g. emojis, so you will lose full Unicode support if you do this.
I think varchar(20) only requires 21 bytes while varchar(500) only
requires 501 bytes. So the total bytes are 522, less than 767. So why
did I get the error message?
UTF8 requires 3 bytes per character to store the string, so in your case 20 + 500 characters = 20*3+500*3 = 1560 bytes which is more than allowed 767 bytes.
The limit for UTF8 is 767/3 = 255 characters, for UTF8mb4 which uses 4 bytes per character it is 767/4 = 191 characters.
There are two solutions to this problem if you need to use longer column than the limit:
Use "cheaper" encoding (the one that requires less bytes per character)
In my case, I needed to add Unique index on column containing SEO string of article, as I use only [A-z0-9\-] characters for SEO, I used latin1_general_ci which uses only one byte per character and so column can have 767 bytes length.
Create hash from your column and use unique index only on that
The other option for me was to create another column which would store hash of SEO, this column would have UNIQUE key to ensure SEO values are unique. I would also add KEY index to original SEO column to speed up look up.
The answer about why you get error message was already answered by many users here. My answer is about how to fix and use it as it be.
Refer from this link.
Open MySQL client (or MariaDB client). It is a command line tool.
It will ask your password, enter your correct password.
Select your database by using this command use my_database_name;
Database changed
set global innodb_large_prefix=on;
Query OK, 0 rows affected (0.00 sec)
set global innodb_file_format=Barracuda;
Query OK, 0 rows affected (0.02 sec)
Go to your database on phpMyAdmin or something like that for easy management. > Select database > View table structure > Go to Operations tab. > Change ROW_FORMAT to DYNAMIC and save changes.
Go to table's structure tab > Click on Unique button.
Done. Now it should has no errors.
The problem of this fix is if you export db to another server (for example from localhost to real host) and you cannot use MySQL command line in that server. You cannot make it work there.
Specified key was too long; max key length is 767 bytes
You got that message because 1 byte equals 1 character only if you use the latin-1 character set. If you use utf8, each character will be considered 3 bytes when defining your key column. If you use utf8mb4, each character will be considered to be 4 bytes when defining your key column. Thus, you need to multiply your key field's character limit by, 1, 3, or 4 (in my example) to determine the number of bytes the key field is trying to allow. If you are using uft8mb4, you can only define 191 characters for a native, InnoDB, primary key field. Just don't breach 767 bytes.
5 workarounds:
The limit was raised in 5.7.7 (MariaDB 10.2.2?). And it can be increased with some work in 5.6 (10.1).
If you are hitting the limit because of trying to use CHARACTER SET utf8mb4. Then do one of the following (each has a drawback) to avoid the error:
⚈ Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
⚈ Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
⚈ ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
⚈ Use a "prefix" index -- you lose some of the performance benefits.
⚈ Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC; -- (or COMPRESSED)
-- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
you could add a column of the md5 of long columns
For laravel 5.7 to 9.0
Steps to followed
Go to App\Providers\AppServiceProvider.php.
Add this to provider use Illuminate\Support\Facades\Schema; in top.
Inside the Boot function Add this Schema::defaultStringLength(191);
that all, Enjoy.
We encountered this issue when trying to add a UNIQUE index to a VARCHAR(255) field using utf8mb4. While the problem is outlined well here already, I wanted to add some practical advice for how we figured this out and solved it.
When using utf8mb4, characters count as 4 bytes, whereas under utf8, they could as 3 bytes. InnoDB databases have a limit that indexes can only contain 767 bytes. So when using utf8, you can store 255 characters (767/3 = 255), but using utf8mb4, you can only store 191 characters (767/4 = 191).
You're absolutely able to add regular indexes for VARCHAR(255) fields using utf8mb4, but what happens is the index size is truncated at 191 characters automatically - like unique_key here:
This is fine, because regular indexes are just used to help MySQL search through your data more quickly. The whole field doesn't need to be indexed.
So, why does MySQL truncate the index automatically for regular indexes, but throw an explicit error when trying to do it for unique indexes? Well, for MySQL to be able to figure out if the value being inserted or updated already exists, it needs to actually index the whole value and not just part of it.
At the end of the day, if you want to have a unique index on a field, the entire contents of the field must fit into the index. For utf8mb4, this means reducing your VARCHAR field lengths to 191 characters or less. If you don't need utf8mb4 for that table or field, you can drop it back to utf8 and be able to keep your 255 length fields.
I fixed this issue with :
varchar(200)
replaced with
varchar(191)
all the unique or primary varchar keys which have more than 200 replace them with 191 or set them as text.
Here is my original answer:
I just drop database and recreate like this, and the error is gone:
drop database if exists rhodes; create database rhodes default
CHARACTER set utf8 default COLLATE utf8_general_ci;
However, it doesn't work for all the cases.
It is actually a problem of using indexes on VARCHAR columns with the character set utf8 (or utf8mb4), with VARCHAR columns that have more than a certain length of characters. In the case of utf8mb4, that certain length is 191.
Please refer to the Long Index section in this article for more information how to use long indexes in MySQL database: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-character-set-to-utf8mb4
To fix that, this works for me like a charm.
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
I did some search on this topic finally got some custom change
For MySQL workbench 6.3.7 Version Graphical inter phase is available
Start Workbench and select the connection.
Go to management or Instance and select Options File.
If Workbench ask you permission to read configuration file and then allow it by pressing OK two times.
At center place Administrator options file window comes.
Go To InnoDB tab and check the innodb_large_prefix if it not checked in the General section.
set innodb_default_row_format option value to DYNAMIC.
For Versions below 6.3.7 direct options are not available so need to go with command prompt
Start CMD as administrator.
Go To director where mysql server is install Most of cases its at
"C:\Program Files\MySQL\MySQL Server 5.7\bin" so command is
"cd \"
"cd Program Files\MySQL\MySQL Server 5.7\bin".
Now Run command
mysql -u userName -p databasescheema
Now it asked for password of respective user.
Provide password and enter into mysql prompt.
We have to set some global settings enter the below commands one by one
set global innodb_large_prefix=on;
set global innodb_file_format=barracuda;
set global innodb_file_per_table=true;
Now at the last we have to alter the ROW_FORMAT of required table by default its COMPACT we have to set it to DYNAMIC.
use following command
alter table table_name ROW_FORMAT=DYNAMIC;
Done
change your collation. You can use utf8_general_ci that supports almost all
Just changing utf8mb4 to utf8 when creating tables solved my problem. For example: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; to CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.
Index Lengths & MySQL / MariaDB
Laravel uses the utf8mb4 character set by default, which includes support for storing "emojis" in the database. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the Schema::defaultStringLength method within your AppServiceProvider:
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
Alternatively, you may enable the innodb_large_prefix option for your database. Refer to your database's documentation for instructions on how to properly enable this option.
Reference from blog : https://www.scratchcode.io/specified-key-too-long-error-in-laravel/
Reference from Official laravel documentation : https://laravel.com/docs/5.7/migrations
This solved my issue
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Based on the column given below, those 2 variable string columns are using utf8_general_ci collation (utf8 charset is implied).
In MySQL, utf8 charset uses a maximum of 3 bytes for each character. Thus, it would need to allocate 500*3=1500 bytes, which is much greater than the 767 bytes MySQL allows. That's why you are getting this 1071 error.
In other words, you need to calculate the character count based on the charset's byte representation as not every charset is a single byte representation (as you presumed.) I.E. utf8 in MySQL is uses at most 3-byte per character, 767/3≈255 characters, and for utf8mb4, an at most 4-byte representation, 767/4≈191 characters.
It's also known that MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
In my case, I had this problem when I was backing up a database using the linux redirection output/input characters. Therefore, I change the syntax as described below. PS: using a linux or mac terminal.
Backup (without the > redirect)
# mysqldump -u root -p databasename -r bkp.sql
Restore (without the < redirect )
# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql
The error "Specified key was too long; max key length is 767 bytes" simple disappeared.
I found this query useful in detecting which columns had an index violating the max length:
SELECT
c.TABLE_NAME As TableName,
c.COLUMN_NAME AS ColumnName,
c.DATA_TYPE AS DataType,
c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
ON s.table_name = c.TABLE_NAME
AND s.COLUMN_NAME = c.COLUMN_NAME
WHERE c.TABLE_SCHEMA = DATABASE()
AND c.CHARACTER_MAXIMUM_LENGTH > 191
AND c.DATA_TYPE IN ('char', 'varchar', 'text')
Please check if sql_mode is like
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
if it is, change to
sql_mode=NO_ENGINE_SUBSTITUTION
OR
restart your server changing your my.cnf file (putting following)
innodb_large_prefix=on
Due to prefix limitations this error will occur. 767 bytes is the stated prefix limitation for InnoDB tables in MySQL versions before 5.7 . It's 1,000 bytes long for MyISAM tables. In MySQL version 5.7 and upwards this limit has been increased to 3072 bytes.
Running the following on the service giving you the error should resolve your issue. This has to be run in the MYSQL CLI.
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;
The Problem
There are max key length limits in MySQL.
InnoDB — max key length is 1,536 bytes (for 8kb page size) and 768 (for 4kb page size) (Source: Dev.MySQL.com).
MyISAM — max key length is 1,000 bytes (Source Dev.MySQL.com).
These are counted in bytes! So, a UTF-8 character may take more than one byte to be stored into the key.
Therefore, you have only two immediate solutions:
Index only the first n'th characters of the text type.
Create a FULL TEXT search — Everything will be Searchable within the Text, in a fashion similar to ElasticSearch
Indexing the First N'th Characters of a Text Type
If you are creating a table, use the following syntax to index some field's first 255 characters: KEY sometextkey (SomeText(255)). Like so:
CREATE TABLE `MyTable` (
`id` int(11) NOT NULL auto_increment,
`SomeText` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `sometextkey` (`SomeText`(255))
);
If you already have the table, then you can add a unique key to a field with: ADD UNIQUE(ConfigValue(20));. Like so:
ALTER TABLE
MyTable
ADD UNIQUE(`ConfigValue`(20));
If the name of the field is not a reserved MySQL keyword, then the backticks (```) are not necessary around the fieldname.
Creating a FULL TEXT Search
A Full Text search will allow you to search the entirety of the value of your TEXT field. It will do whole-word matching if you use NATURAL LANGUAGE MODE, or partial word matching if you use one of the other modes. See more on the options for FullText here: Dev.MySQL.com
Create your table with the text, and add the Full text index...
ALTER TABLE
MyTable
ADD FULLTEXT INDEX
`SomeTextKey` (`SomeTextField` DESC);
Then search your table like so...
SELECT
MyTable.id, MyTable.Title,
MATCH
(MyTable.Text)
AGAINST
('foobar' IN NATURAL LANGUAGE MODE) AS score
FROM
MyTable
HAVING
score > 0
ORDER BY
score DESC;
I have changes from varchar to nvarchar, works for me.