在MySQL中,将TINYTEXT作为主键是否可行?

3

我的表中的每个条目都由一个长度为5-10个字符的单词唯一标识,并且我在该列中使用了TINYTEXT(10)。然而,当我尝试将其设置为PRIMARY键时,我会收到错误消息,提示缺少size

根据我对文档的有限理解,PRIMARY键的size可用于简化检测唯一值的方式,即当前几个字符(由Size指定)足以被视为唯一匹配项。在我的情况下,size将从5到10不等(它们都是latin1编码,所以每个字符占用确切的字节+1用于长度)。两个问题:

  1. 如果我想将TINYTEXT用作PRIMARY键,应该指定哪个size?在这种情况下,最大可用大小是10吗?还是应该严格确切地指定size,例如,如果我的键是6个字符长的单词,但我将PK的Size指定为10,则它将尝试读取所有10个字符并失败并抛出异常?
  2. 在性能方面,使用[TINY]TEXT作为PK有多糟糕?所有的谷歌结果都导致了"这很糟糕,你被解雇了"的言论和声明,但考虑到TINYTEXT的最大长度为255,我已经将其最大长度指定为10,这是否真的属实?

你为什么想使用TINYTEXT而不是VARCHAR? - gview
@gview 是的,我不需要超过10个字符,而TINYTEXT是非填充255长。VARCHAR有自己的打包问题,因为它可以达到65k长。 - Kirikan
1
varchar 只需要存储使用的字节数 + 1 字节的长度。它不像 char。如果你声明一个 varchar[10],你可以存储最多 10 个字符,但是如果你只使用了 5 个字符,那么它只需要 5 + 1 个字节。最坏情况下需要 11 个字节。 - gview
@gview - 最坏情况是41个字节 -- 如果字符集为utf8mb4。 - Rick James
使用 VARCHAR,不要使用 TINYTEXT。而且不要使用前缀。句号。 - Rick James
@RickJames:是的,UTF-8每个字符占用1-4个字节,但这与其他字符类型没有区别。 - gview
3个回答

5
  1. MySQL/MariaDB can index only the first characters of the text fields but not the whole text if it is too large. The maximum key size is 3072 bytes and any text field larger than that cannot be used as KEY. Therefore on text fields longer than 3072 bytes you must specify explicitly how much characters it will index. When using VARCHAR or CHAR it can be done directly because you explicitly set it when declaring the datatype. It's not the case with *TEXT - they do not have that option. The solution is to create the primary key like this:

    CREATE TABLE mytbl (
        name TEXT NOT NULL,
        PRIMARY KEY idx_name(name(255))
    );
    

    The same trick can be done if you need to make primary key on a VARCHAR field which is larger than 3072 bytes, on BINARY fields and BLOBs. Anyway you can imagine that if two large and different texts start with the same characters at the first 3072 bytes at the beginning, they will be treated as equal by the system. That may be a problem.

  2. It is generally bad idea to use text field as primary key. There are two reasons for that:

    2.1. It takes much more processing time than using integers to search in the table (WHERE, JOINS, etc). The link is old but still relevant;

    2.2. Any foreign key in another table must have the same datatype as the primary key. When you use text, this will waste disk space;

注意:*TEXT 和 VARCHAR 的区别在于 *TEXT 字段的内容不会存储在表中,而是存储在外部内存位置。通常我们这样做是因为需要存储非常大的文本。


我修改了我的回答,因为我的第一版中的第一点是错误的(我说它不能完成)。事实上,它可以完成 :) - Philip Petrov
“通常不建议使用文本字段作为主键”--是的,避免使用TEXT作为主键。如果你恰好有两行具有不同TEXT值但在开头共享完全相同的3072个字符,那么插入操作将会[错误地]失败。 - The Impaler

3

你没有指定字段的最大大小,但可以指定索引的大小。请查看我对这个问题的回答。 - Philip Petrov

0

顺便提一下,在MySQL中你无法为TINYTEXT指定大小:

mysql> create table t1 ( t tinytext(10) );
ERROR 1064 (42000): 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 '(10) )' at line 1

你可以在TEXT后面指定一个长度,但它的工作方式并不是你想象的那样。这意味着它会选择 TEXT 类型中支持至少请求的长度的最小类型。但一旦它这样做了,它就不限制输入的长度。它仍然接受任何数据,直到所选类型的最大长度。
mysql> create table t1 ( t text(10) );
Query OK, 0 rows affected (0.02 sec)

mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `t` tinytext
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

mysql> insert into t1 set t = repeat('a', 255);
Query OK, 1 row affected (0.01 sec)

mysql> select length(t) from t1;
+-----------+
| length(t) |
+-----------+
|       255 |
+-----------+

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接