【发布时间】:2026-02-18 00:25:02
【问题描述】:
请帮助我了解如何在 MySQL utf8mb4 字段中处理表情符号等多字节字符。
请参阅下面的简单测试 SQL 来说明挑战。
/* Clear Previous Test */
DROP TABLE IF EXISTS `emoji_test`;
DROP TABLE IF EXISTS `emoji_test_with_unique_key`;
/* Build Schema */
CREATE TABLE `emoji_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`string` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`status` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `emoji_test_with_unique_key` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`string` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`status` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_string_status` (`string`,`status`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/* INSERT data */
# Expected Result is successful insert for each of these.
# However some fail. See comments.
INSERT INTO emoji_test (`string`, `status`) VALUES ('????', 1); # SUCCESS
INSERT INTO emoji_test (`string`, `status`) VALUES ('????', 1); # SUCCESS
INSERT INTO emoji_test (`string`, `status`) VALUES ('????????', 1); # SUCCESS
INSERT INTO emoji_test (`string`, `status`) VALUES ('????????', 1); # SUCCESS
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('????', 1); # SUCCESS
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('????', 1); # FAIL: Duplicate entry '?-1' for key 'idx_string_status'
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('????????', 1); # SUCCESS
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('????????', 1); # FAIL: Duplicate entry '??-1' for key 'idx_string_status'
/* Test data */
/* Simple Table */
SELECT * FROM emoji_test WHERE `string` IN ('????','????','????????','????????'); # SUCCESS (all 4 are found)
SELECT * FROM emoji_test WHERE `string` IN ('????'); # FAIL: Returns both ???? and ????
SELECT * FROM emoji_test WHERE `string` IN ('????'); # FAIL: Returns both ???? and ????
SELECT * FROM emoji_test; # SUCCESS (all 4 are found)
/* Table with Unique Key */
SELECT * FROM emoji_test_with_unique_key WHERE `string` IN ('????','????','????????','????????'); # FAIL: Only 2 are found (due to insert errors above)
SELECT * FROM emoji_test_with_unique_key WHERE `string` IN ('????'); # SUCCESS
SELECT * FROM emoji_test_with_unique_key WHERE `string` IN ('????'); # FAIL: ???? found instead of ????
SELECT * FROM emoji_test_with_unique_key; # FAIL: Only 2 records found (???? and ????????)
我有兴趣了解导致上述FAILs 的原因以及如何解决此问题。
具体来说:
- 为什么选择一个多字节字符会返回任何个多字节字符的结果?
- 如何配置索引来处理多字节字符而不是
?? - 您能否建议对上面的第二个
CREATE TABLE(具有唯一键的那个)进行更改,以使所有测试查询都成功返回?
【问题讨论】:
-
任何墨西哥人都可以告诉你,???? ('TACO' (U+1F32E)) 和???? ('HOT PEPPER' (U+1F336)) 显然相关但不同。这一定是多年来写得最精彩的问题。
-
相关:*.com/questions/38116984/…:解决方案是使用 MySQL 5.6+ 并使用 utf8mb4_unicode_520_ci 排序规则,它不会将所有 4 字节字符视为相等 - 一个很好的理由避免使用表情符号作为密码:)
-
@ÁlvaroGonzález 好吧,如果这是密码的问题,那么给定的设置会有更大的问题,因为密码应该使用单向哈希存储。对于散列,它不应该是个问题。但我也不建议将它们用作密码。