我有下表:
CREATE TABLE `tokens` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`s_id` int(10) unsigned NOT NULL,
`a_token` char(40) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`a_token_exp` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_a_token` (`a_token`) USING HASH,
KEY `f_seid` (`s_id`),
CONSTRAINT `f_seid` FOREIGN KEY (`s_id`) REFERENCES `sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1
我想更改字符集,a_token
因为我们使用此命令仅使用 ascii 字符:
ALTER TABLE tokens MODIFY a_token CHAR(40) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL;
和新SHOW CREATE TABLE
节目:
CREATE TABLE `tokens` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id` int(10) unsigned NOT NULL,
`a_token` char(40) CHARACTER SET ascii NOT NULL,
`a_token_exp` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_a_token` (`a_token`) USING HASH,
KEY `f_seid` (`s_id`),
CONSTRAINT `f_seid` FOREIGN KEY (`s_id`) REFERENCES `sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1
然后我跑OPTIMIZE TABLE oauth_session_access_tokens
。
此查询应该(我不确定)我的架构的表大小:
SELECT table_name AS "Table",
((data_length + index_length)) AS "Size"
FROM information_schema.TABLES
WHERE table_schema = "test"
ORDER BY (data_length + index_length) DESC;
但特定表在.之前和之后tokens
总是返回49152ALTER TABLE
我可以假设即使使用 CHAR 和 utf8,如果只有 ASCII 字符,那么该字段不会为 utf8 预先分配空间?
UTF-8 是一种变长字符编码。对于 ASCII 范围内的字符,每个字符只占用 1 个字节。对于那些需要它的字符,它每个字符只使用 2、3 或 4 个字节。
关于 UTF-8 的维基百科文章对多字节编码的工作方式有很好的解释和说明。https://en.wikipedia.org/wiki/UTF-8
因此,即使您只有 ASCII 字符要存储,使用 UTF-8 也没有什么缺点。
简短回答:是的,切换到 ASCII。
Looooong 回答:这个问题有很多方面。
VARCHAR
而不是CHAR
.CHAR
. (40 听起来像 SHA1,它是固定长度)。UNHEX()
在存储和HEX()
获取时使用,然后存储到一半大小的BINARY
或VARBINARY
列中(BINARY(20)
对于 SHA1)。这为 Ascii 节省了每行 20 个字节。CHAR
填充到给定的长度。CHAR
。utf8
这可能是您的主要问题。CHAR
orVARCHAR
,请考虑COLLATION
使用什么。对于十六进制,任何以结尾的排序规则_ci
都可能是合适的。(对于 Base64 文本,_bin
是合适的。)INT UNSIGNED
溢出大约 40 亿行。)Ascii
并latin1
执行类似的操作。