MySQL 預設字符集校對規則多為 _ci(Case Insensitive,不區分大小寫)。若需精確匹配大小寫,有兩種方式:
SELECT * FROM `usertest` WHERE `username` LIKE BINARY '%夏%';
SELECT * FROM `usertest` WHERE `username` = BINARY '夏';
BINARY 會將字符串轉為二進制字節逐位比較,效率略低於預設校對,但語義精確。
-- 建表時指定
CREATE TABLE `usertest` (
`username` VARCHAR(30) BINARY NOT NULL DEFAULT ''
);
-- 修改既有表
ALTER TABLE `usertest` MODIFY `username` VARCHAR(32) BINARY;
這樣該欄位的所有比較、排序、分組預設都區分大小寫,避免應用層遺漏。
| 特性 | CHAR(N) | VARCHAR(N) |
|---|---|---|
| 長度 | 固定長度,不足右補空格 | 可變長度,實際長度+1/2字節存長度 |
| 存儲單位 | 字符 | 字符 |
| 編碼佔用 | gbk: 2字節/字符; utf8mb4: 3-4字節/字符 | 同左,另加長度前綴 |
| 尾部空格 | 存入自動去除,比較時忽略 | 存入保留,比較時忽略 |
| 碎片風險 | 無(固定長度) | 頻繁更新易產生碎片 |
| 適用場景 | MD5、UUID、手機號、身分證等定長高頻更新短字段 | 長度不固定、平均長度遠小於上限的字段 |
CREATE TABLE `zcy` (
`name` VARCHAR(4),
`addr` CHAR(8)
);
INSERT INTO `zcy` VALUES ('a ', 'a'), ('a', 'a ');
SELECT CONCAT('$', `name`, '$') AS n, CONCAT('$', `addr`, '$') AS a FROM `zcy`;
-- 結果:
-- n: $a$ (varchar 存入 a 去尾空格 -> 'a')
-- a: $a$ (char 存入 a 补齐空格 -> 'a ', 但比較時忽略尾部空格)
SELECT * FROM `zcy` WHERE `name` = 'a '; -- 命中 'a' 和 'a ' 兩行
SELECT * FROM `zcy` WHERE `addr` = 'a '; -- 命中 'a' 和 'a ' 兩行
BINARY(N):固定長度,不足右補 \0 (0x00),非空格。VARBINARY(N):可變長度,不補齊,存實際字節。-- BINARY 比較需精確匹配 \0
SELECT * FROM `zcy` WHERE `b` = 'a\0\0\0\0\0\0\0'; -- 僅匹配存入 'a' 補齊 \0 的行
SELECT * FROM `zcy` WHERE `bn` = 'ab '; -- VARBINARY 嚴格匹配字節,'ab ' 包含空格字節 0x20
| 維度 | BLOB 系列 | TEXT 系列 |
|---|---|---|
| 本質 | 二進制字串 (字節串) | 非二進制字串 (字符串) |
| 字符集 | 無 | 有,按字符集校對規則排序比較 |
| 大小寫轉換 | 無 | 無 |
| 尾部空格 | 存儲/檢索不刪除,比較時擴充空格 | 同左 |
| 索引 | 必須指定前綴長度 | 必須指定前綴長度 |
| 默認值 | 不支援 | 不支援 |
| 類比 | 超大 VARBINARY | 超大 VARCHAR |
ORDER BY blob_col 僅用前 max_sort_length (預設 1024) 字節。解決:SET SESSION max_sort_length=2000; 或 ORDER BY SUBSTRING(blob_col, 1, 2000)。max_allowed_packet 限制,客戶端與服務端需同步調大。CHAR 或 BINARY。VARCHAR (配合 utf8mb4_general_ci 或 utf8mb4_0900_ai_ci)。BINARY 或用 VARBINARY。BLOB 系列(建議存檔案路徑,DB 只存元數據)。TEXT 系列,注意索引前綴與排序截斷。utf8mb4,杜絕亂碼與隱式轉換效能損耗。