I am trying to make a order system, but I am stuck right now.
In the mysql tabel right now, I am using varchar(255) in a column named "bestillinger", but it can only store 255 chars. So I searched a bit, and remembered that i could use longtext or just text, but now when i try to do it, i get a error saying:
#1170 - BLOB/TEXT column 'bestilling' used in key specification without a key length
I have tried to search here and in Google, but got no luck with me.
My MySQL tabel is:
CREATE TABLE IF NOT EXISTS `bestillinger` (
`id` int(11) NOT NULL,
`bestilling` TEXT NOT NULL PRIMARY KEY,
`accepted` varchar(255) DEFAULT NULL,
UNIQUE KEY `id_bestilling` (`id`,`bestilling`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
I am using UNIQUE KEY because I am using "ON DUPLICATE KEY UPDATE" in my PHP part. But don't mind that.
Thanks in advance.
you can't set a text as a primary key. Mysql only can Index some characters, and type text could be too big to index.
take a look here:
http://www.mydigitallife.info/mysql-error-1170-42000-blobtext-column-used-in-key-specification-without-a-key-length/
MySQL error: key specification without a key length
From your definition above, and the verbose monologue in this answer below I suggest the following revision:
CREATE TABLE IF NOT EXISTS `bestillinger` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`bestilling` TEXT NOT NULL,
`hashcode` CHAR(32) AS (MD5(bestilling)),
`accepted` VARCHAR(255) DEFAULT NULL,
UNIQUE KEY `id_bestilling` (hashcode,bestilling(333))
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Specific to MySQL, the default max length for a single-column index key is 1000 bytes long (767 bytes for InnoDB tables, unless you have innodb_large_prefix set). The same length limit applies to any index key prefix (the first N characters for CHAR, VARCHAR, TEXT or first N bytes for BINARY, VARBINARY, BLOB). Note the character versus byte difference; assuming a UTF-8 character set and the maximum of 3 bytes for each character, you might hit this limit with a column prefix index of more than 333 characters on a TEXT or VARCHAR column. In practice, 333 tends to be a good max for me.
Similarly in SQL Server, there is a 900-byte limit for the maximum total size of all index key columns.
But that only uses the first characters of your TEXT as your key, with the obvious collisions imminent.
In the accepted answer, the suggestion is to use a FULLTEXT index. A FULLTEXT index is specially designed for text searching, and it has not-so-good performance for INSERT/DELETE since it maintains an N-gram over the vocabulary of the column records and stores the resulting vector. This would work if every operation were to use text search functions in a where clause...but not for a unique index. There is also both a primary key and a unique key defined on 'id', which seems redundant or I miss the intent.
Instead, I suggest a computed hash. you'd be correct to point out there is a chance (Birthday Paradox) that there will be a collision with a hash, so a UNIQUE index alone isn’t enough. We'll couple it with a column prefix index, as described above, to give us faith in the uniqueness.
I gather the intent of your ID column is to allow proper foreign key referencing from other tables. Quite right, but then that would be the more useful primary key for this table. As well, int(11) refers to the display width of the column, not the underlying value. I put an unsigned auto_increment on 'id' as well, to clarify its role for the larger audience.
And that brings us to the proposed design above.
use this
CREATE TABLE IF NOT EXISTS `bestillinger` (
`id` int(11) NOT NULL,
`bestilling` TEXT NOT NULL PRIMARY KEY,
`accepted` varchar(255) DEFAULT NULL,
UNIQUE KEY `id_bestilling` (`id`,`bestilling`(767))
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
767 is the limit in mysql while dealing with blob/text indexes
Ref : http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
I think the following example will best explain this problem.
I got the problem because I was trying to set a text field to UNIQUE. I fixed the problem by changing data type of email(TEXT) to email(VARCHAR(254)).
mysql> desc users;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| fname | varchar(50) | NO | | NULL | |
| lname | varchar(50) | NO | | NULL | |
| uname | varchar(20) | NO | | NULL | |
| email | text | NO | | NULL | |
| contact | bigint(12) | NO | | NULL | |
| profile_pic | text | NO | | NULL | |
| password | varchar(20) | NO | | admin | |
+-------------+-------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)
mysql> ALTER TABLE users ADD UNIQUE(email);
ERROR 1170 (42000): BLOB/TEXT column 'email' used in key specification without a key length
mysql>
mysql> ALTER TABLE users MODIFY email VARCHAR(254);
Query OK, 9 rows affected (0.02 sec)
Records: 9 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE users ADD UNIQUE(email);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc users;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| fname | varchar(50) | NO | | NULL | |
| lname | varchar(50) | NO | | NULL | |
| uname | varchar(20) | NO | | NULL | |
| email | varchar(254) | YES | UNI | NULL | |
| contact | bigint(12) | NO | | NULL | |
| profile_pic | text | NO | | NULL | |
| password | varchar(20) | NO | | admin | |
+-------------+--------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)
mysql>
Try to use all column length in varchar. Text should be not allowed because of size.
Related
I'm learning from an online course MySQL using the WampServer and editing code in MySQL Workbench.
Trying to create a table with the following code, the column nome appears to be the primary key from the table, but i'm only using the unique constraint.
When i don't use the unique constraint, the code runs normally and don't give me a primary key.
create table if not exists cursos (
nome varchar(30) not null unique,
descricao text,
carga int unsigned,
totalaulas int unsigned,
ano year default '2016'
) default charset utf8mb4;
Second to this question, when i was trying to drop the constraint primary key i was getting the error Error Code: 1091. Can't DROP 'PRIMARY';
alter table cursos
drop primary key;
So, in resume, i'm trying to use the unique constraint without setting a column has a primary key, and then i'm trying to drop the primary key constraint.
Edit:
When i call describe table i get this, the column nome is defined has primary key whithout i using the constraint.
+------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+----------------+
| idcurso | int | YES | | NULL | |
| nome | varchar(30) | NO | PRI | NULL | |
+------------------+-------------+------+-----+---------+----------------+
What i'm trying to do is drop the primary key from nome and put on idcurso, but when i use the code
alter table cursos
add primary key idcurso;
I get the error Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line
I tried this on mysql command-line client connected to a MySQL Server 5.5.2. Here is what happens:
mysql> create table if not exists cursos (
-> nome varchar(30) not null unique,
-> descricao text,
-> carga int unsigned,
-> totalaulas int unsigned,
-> ano year default '2016'
-> ) default charset utf8mb4;
Query OK, 0 rows affected (0.08 sec)
mysql>
mysql> desc cursos;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| nome | varchar(30) | NO | PRI | NULL | |
| descricao | text | YES | | NULL | |
| carga | int(10) unsigned | YES | | NULL | |
| totalaulas | int(10) unsigned | YES | | NULL | |
| ano | year(4) | YES | | 2016 | |
+------------+------------------+------+-----+---------+-------+
5 rows in set (0.05 sec)
Note that the field nome has a Key as PRI. But, it is only a description and not a fact. If you try to DROP the primary key you will see an error like below:
mysql> alter table cursos drop primary key;
ERROR 1091 (42000): Can't DROP 'PRIMARY'; check that column/key exists
Add a new column and make it a primary key. Note the DESCRIPTION after that.
mysql> alter table cursos add idcurso int primary key;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc cursos;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| nome | varchar(30) | NO | UNI | NULL | |
| descricao | text | YES | | NULL | |
| carga | int(10) unsigned | YES | | NULL | |
| totalaulas | int(10) unsigned | YES | | NULL | |
| ano | year(4) | YES | | 2016 | |
| idcurso | int(11) | NO | PRI | NULL | |
+------------+------------------+------+-----+---------+-------+
6 rows in set (0.05 sec)
At this point, you can drop the primary key using the syntax: alter table cursos drop primary key;. This will drop the primary key constraint only (but, not the column definition).
If you create yet another column, perhaps guid,
that has a UNIQUE constraint,
then you will be able to do what you wish.
(Not sure why you wish it. Whatever.)
A table can have multiple UNIQUE constraints.
Each table should have a PRIMARY KEY (which will of course be UNIQUE).
It affects physical layout of the rows on disk,
which affects retrieval speed and how the query planner behaves.
If you do not use the PRIMARY keyword, then the first UNIQUE column
will effectively be the primary key.
Put another way, to ALTER the table as you wish,
the backend DB will need to be able to promote
some candidate column so it becomes the new PRIMARY KEY.
Edit: Not sure why this is marked as a duplicate. The error I am getting is different
I am trying to remove a primary key definition but am receiving an error for some reason.
mysql> ALTER TABLE `aux_sponsors` DROP PRIMARY KEY;
ERROR 1091 (42000): Can't DROP 'PRIMARY'; check that column/key exists
mysql> desc aux_sponsors;
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| unit | varchar(8) | NO | | MF | |
| code | varchar(32) | NO | PRI | NULL | |
| userid | varchar(32) | NO | | | |
| fullName | varchar(64) | NO | | | |
| department | varchar(255) | NO | | | |
| description | varchar(255) | NO | | NULL | |
+-------------+--------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
Am I doing something wrong here? I simply want no more primary key in this table.
mysql> SHOW CREATE TABLE aux_sponsors;
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| aux_sponsors | CREATE TABLE `aux_sponsors` (
`unit` varchar(8) NOT NULL DEFAULT 'MF',
`code` varchar(32) NOT NULL,
`userid` varchar(32) NOT NULL DEFAULT '',
`fullName` varchar(64) NOT NULL DEFAULT '',
`department` varchar(255) NOT NULL DEFAULT '',
`description` varchar(255) NOT NULL,
UNIQUE KEY `code` (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
You don't have a PRIMARY KEY; you have a UNIQUE key. So, you can't do this:
ALTER TABLE `aux_sponsors` DROP PRIMARY KEY
Instead, just do
ALTER TABLE `aux_sponsors` DROP KEY `code`
DESC (a/k/a DESCRIBE) is not a true MySQL feature; according to the docs, "The DESCRIBE statement is provided for compatibility with Oracle."
More from the documentation:
A UNIQUE index may be displayed as PRI if it cannot contain NULL values and there is no PRIMARY KEY in the table. A UNIQUE index may display as MUL if several columns form a composite UNIQUE index; although the combination of the columns is unique, each column can still hold multiple occurrences of a given value.
In your case, the column code is NOT NULL and is the only column in a UNIQUE key, so DESC is showing it as PRI. Because of this type of problem, it's better to use SHOW INDEX to find out the types of keys on a table.
I am trying to change an existing column in a table I have to allow for null values and then set the default value to null. I tried running the following but it does not seem to be updating the table:
mysql> ALTER TABLE answers_form MODIFY sub_id int unsigned NULL DEFAULT NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc answers_form;
+--------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+-------+
| answer_id | int(10) unsigned | NO | PRI | 0 | |
| sub_id | int(10) unsigned | NO | PRI | 0 | |
| form_id | int(10) unsigned | NO | PRI | NULL | |
| value | varchar(255) | NO | | NULL | |
| non_response | bit(1) | YES | | b'0' | |
+--------------+------------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
Can anyone see what I am doing wrong here?
its a primary key , mysql doesn't allow any part of the primary key to be null, which does make the fact that it allows a default value of null for the form_id odd, however the docs at
http://dev.mysql.com/doc/refman/5.5/en/optimizing-primary-keys.html
say "Query performance benefits from the NOT NULL optimization, because it cannot include any NULL values".
Just out of curiosity, does it actually allow you to put in null values in the form_id field?
You have 2 non-nullable columns with the default value of null. This shouldn't be allowed by your database engine. If it is, it is rather far from a best practice.
sub_id is listed as a primary key
From the MySQL docs (5.7, but other versions say the same thing):
A PRIMARY KEY is a unique index where all key columns must be defined
as NOT NULL. If they are not explicitly declared as NOT NULL, MySQL
declares them so implicitly (and silently).
As to the discussion about the Non-null columns having a Default of NULL...
The NULL value in the Default column means that there is no default, not that the default is NULL.
Fiddle: http://sqlfiddle.com/#!2/c718d/1
If I create a simple table like so:
CREATE TABLE name_num(
Number INT PRIMARY KEY,
Name TEXT NOT NULL
);
And then do desc name_num, I get:
| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
---------------------------------------------------
| Number | int(11) | NO | PRI | (null) | |
| Name | text | NO | | (null) | |
Again, from the MySQL docs:
If the column cannot take NULL as the value, MySQL defines the column with no explicit DEFAULT clause. Exception: If the column is defined as part of a PRIMARY KEY but not explicitly as NOT NULL, MySQL creates it as a NOT NULL column (because PRIMARY KEY columns must be NOT NULL), but also assigns it a DEFAULT clause using the implicit default value. To prevent this, include an explicit NOT NULL in the definition of any PRIMARY KEY column.
I have a mysql table with a compound primary key. The table definition looks like(some column omitted):
CREATE TABLE `wasteitem` (
`categoryid` char(4) NOT NULL,
`classid` char(4) NOT NULL,
`LIflag` int(11) NOT NULL,
PRIMARY KEY (`categoryid`,`classid`)
);
And I want to determine if any of known keys have been used.
If the table have only a simple primary key I can use query like this:
select categoryid from wasteitem where categoryid in ('key1','key2','key3','key4')
Things to be concerned:
The primary key is a compound key.
The known keys in the list might be very long.
This table is very big(26GB)
You could put the keys you're interested in in another (temporary) table, and join.
use it, to look for keys
DESCRIBE wasteitem
that would be something similar:
mysql> describe wasteitem;
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| categoryid | char(4) | NO | PRI | NULL | |
| classid | char(4) | NO | PRI | NULL | |
| LIflag | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
I have a database with the following stats
Tables Data Index Total
11 579,6 MB 0,9 GB 1,5 GB
So as you can see the Index is close to 2x bigger. And there is one table with ~7 million rows that takes up at least 99% of this.
I also have two indexes that are very similar
a) UNIQUE KEY `idx_customer_invoice` (`customer_id`,`invoice_no`),
b) KEY `idx_customer_invoice_order` (`customer_id`,`invoice_no`,`order_no`)
Update: Here is the table definition (at least structurally) of the largest table
CREATE TABLE `invoices` (
`id` int(10) unsigned NOT NULL auto_increment,
`customer_id` int(10) unsigned NOT NULL,
`order_no` varchar(10) default NULL,
`invoice_no` varchar(20) default NULL,
`customer_no` varchar(20) default NULL,
`name` varchar(45) NOT NULL default '',
`archived` tinyint(4) default NULL,
`invoiced` tinyint(4) default NULL,
`time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`group` int(11) default NULL,
`customer_group` int(11) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_customer_invoice` (`customer_id`,`invoice_no`),
KEY `idx_time` (`time`),
KEY `idx_order` (`order_no`),
KEY `idx_customer_invoice_order` (`customer_id`,`invoice_no`,`order_no`)
) ENGINE=InnoDB AUTO_INCREMENT=9146048 DEFAULT CHARSET=latin1 |
Update 2:
mysql> show indexes from invoices;
+----------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| invoices | 0 | PRIMARY | 1 | id | A | 7578066 | NULL | NULL | | BTREE | |
| invoices | 0 | idx_customer_invoice | 1 | customer_id | A | 17 | NULL | NULL | | BTREE | |
| invoices | 0 | idx_customer_invoice | 2 | invoice_no | A | 7578066 | NULL | NULL | YES | BTREE | |
| invoices | 1 | idx_time | 1 | time | A | 541290 | NULL | NULL | | BTREE | |
| invoices | 1 | idx_order | 1 | order_no | A | 6091 | NULL | NULL | YES | BTREE | |
| invoices | 1 | idx_customer_invoice_order | 1 | customer_id | A | 17 | NULL | NULL | | BTREE | |
| invoices | 1 | idx_customer_invoice_order | 2 | invoice_no | A | 7578066 | NULL | NULL | YES | BTREE | |
| invoices | 1 | idx_customer_invoice_order | 3 | order_no | A | 7578066 | NULL | NULL | YES | BTREE | |
+----------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
My questions are:
Is there a way to find unused indexes in MySQL?
Are there any common mistakes that impact the size of the index?
Can indexA safely be removed?
How can you measure the size of each index? All I get is the total of all indexes.
You can remove index A, because, as you have noted, it is a subset of another index. And it's possible to do this without disrupting normal processing.
The size of the index files is not alarming in itself and it can easily be true that the net benefit is positive. In other words, the usefulness and value of an index shouldn't be discounted because it results in a large file.
Index design is a complex and subtle art involving a deep understanding of the query optimizer explanations and extensive testing. But one common mistake is to include too few fields in an index in order to make it smaller. Another is to test indexes with insufficient, or insufficiently representative data.
I may be wrong, but the first index (idx_customer_invoice) is UNIQUE, the second (idx_customer_invoice_order) is not, so you'll probably lose the uniqueness constraint when you remove it. No?
Is there a way to find unused indexes in MySQL?
The database engine optimizer will select a proper index when attempting to optimize your query. Depending on when you collected statistics on your indexes last, the index which is chosen will vary. Unused indexes could suddenly become used because of new data repartition.
Can indexA safely be removed?
I would say yes, if indexA and indexB are B-Tree indexes. This is because an index that starts with the same columns in the same order will have the same structure.
use
show indexes from table;
to define what indexes do you have in a particular table. Cardinality would tell how useful your index is.
You can remove your indexes safely (it will not break a table), but beware: some queries might execute slower. First you should analyze your queries to decide whether you need a certain index or not.
I don't think you can find out data length of a particular index, though.
BUT, I think you probably think that if indexes length is greater than data length twice is something abnormal... Well, you are wrong. All of your indexes might be useful ;) If you have a table that provides a lot of information and you have to search on it upon a large number of column, it can easily be that indexes of this table will 2 times bigger in size that the tables data.
indexA can remove because there's a
indexB include indexA
what impact your index length is
your column type and column length
use:
select index_length from information_schema.tables
where table_name='your_table_name' and
table_schema='your_db_name';
get your table index_length